diff --git a/ci/cppcheck-misra.sh b/ci/cppcheck-misra.sh
index 96e0c9cda223ce6b1bae4c330fff5e7a072ff600..529f96aee9be670dcce09b11b086dcc853ee7513 100755
--- a/ci/cppcheck-misra.sh
+++ b/ci/cppcheck-misra.sh
@@ -14,17 +14,11 @@ curl https://raw.githubusercontent.com/danmar/cppcheck/f4b5b156d720c712f6ce99f6e
 
 # generate dump files (XML representations of AST etc.) for all headers, source files etc.
 echo -e "\u001b[34;1mGenerating dump files...\u001b[0m"
-for file in $(find inc/ src/ -type f \( -iname "*.cpp" -or -iname "*.hpp" \))
-do 
-    cppcheck --dump $file
-done
+find inc/ src/ -type f \( -iname "*.cpp" -or -iname "*.hpp" \) | xargs cppcheck --dump
 
 # run the MISRA checks against the dumps and send the results to a file
 echo -e "\u001b[34;1mRunning MISRA C(2012) rule compliance tests...\u001b[0m"
-for file in $(find inc/ src/ -type f -name "*.dump")
-do 
-    python ci/misra.py $file >> ci/report.msr 2>&1
-done
+find inc/ src/ -type f -name "*.dump" | xargs python3 ci/misra.py >> ci/report.msr 2>&1
 
 # pre-process the generated report to remove all useless strings
 echo -e "\u001b[34;1mPre-processing report...\u001b[0m"
@@ -32,4 +26,4 @@ sed -i -r 's/(.*Script.*)|(.*Checking.*)|(.*MISRA.*)//gm; /(^$)/d; s/(\s\(.*\)\s
 
 # run the summarizer for a nice, clean summary of errors
 echo -e "\u001b[34;1mSummarizing results...\u001b[0m"
-python ci/summarizer.py ci/report.msr
+python3 ci/summarizer.py ci/report.msr
diff --git a/ci/summarizer.py b/ci/summarizer.py
index 60090ef370632aa97336ac39cc519c3989223f14..b7a3aa17a360de5f1bc83720b68a4608493a65d9 100755
--- a/ci/summarizer.py
+++ b/ci/summarizer.py
@@ -1,68 +1,80 @@
-#!/bin/env python
+#!/bin/env python3
 
 from sys import argv
 from sys import exit
 from collections import Counter
 
-'''
+"""
 Naive parser and pretty printer for the MISRA reports by cppcheck
-'''
+"""
 
-script, reportfile = argv
-def analyze():
-    '''
-    A really dumb parser for the pre-processed report generated by cppcheck
-    '''
-    errorsMap = {} # keys: filenames, values: list of tuples containing rule violated and line
-    file = open(reportfile, 'r')
-    fileLines = file.readlines()
-    cppcheckNumOfErrors = len(fileLines) # number of errors in the original report (most of these are duplicates)
-    linesSeen = set() # contains the unique lines from the file
+red = "\033[91m"
+yellow = "\033[93m"
+green = "\033[92m"
+bold = "\033[1m"
+end = "\033[0m"
+
+class Summarizer(object):
+    def __init__(self, report_name):
+        with open(report_name, 'r') as f:
+            self.file_lines = f.readlines()
+        f.close()
+
+    def analyze(self):
+        """
+        A really dumb parser for the pre-processed report generated by cppcheck
+        """
+    
+        errors_map = {} # dictionary containing filenames, rule violations and line where the violation occurred
     
-    if len(fileLines) == 0:
-        print("\033[1m\033[92mStatic analysis for MISRA compliance complete. No errors found.")
-        return 0
-    else:
-        for line in fileLines:  # remove duplicate lines
-            if line not in linesSeen:
-                linesSeen.add(line)
+        lines_seen = set() # contains the unique lines from the file
+    
+        if len(self.file_lines) == 0:
+            print(bold + green + "Static analysis for MISRA compliance complete. No errors found." + end)
+            return 0
+        else:
+            for line in self.file_lines:  # remove duplicate lines
+                if line not in lines_seen:
+                    lines_seen.add(line)
             
-        for line in linesSeen: # after cleaning up the duplicates, split the line into parts
-            lineContents = line.split(':')
-            fileName = lineContents[0] # first part is the filename (index 0)
-            error = (lineContents[1], lineContents[2].strip('\n')) # index 1: line number, index 2: number of violated rule
+                    line_contents = line.split(':')
+                    file_name = line_contents[0] # first part is the filename (index 0)
+                    error = (line_contents[1], line_contents[2].strip('\n')) # index 1 is the line number, index 2 is the number of violated rule
 
-            if fileName not in errorsMap.keys():
-                errorsMap[fileName] = list()  # create a new list for the new filename and append the tuple in it
-                errorsMap[fileName].append(error)
-            else:
-                errorsMap[fileName].append(error) # do not append if it already exists
+                    if file_name not in errors_map.keys():
+                        errors_map[file_name] = list()  # create a new list for the new filename and append the tuple in it
+                        errors_map[file_name].append(error)
+                    else:
+                        errors_map[file_name].append(error) # do not append if it already exists
             
-        return errorsMap # return the completed error dictionary
+            return errors_map # return the completed error dictionary
+
+
+    def pretty_print(self, errors):
+        """
+        Pretty-prints the contents of the error dictionary with colors and stuff
+        """
 
+        print(bold + red + "=================================================\n" + end)
+        print(bold + red + "       Static analysis results: Error Summary        \n" + end)
+        for key in errors:
+            for error in errors[key]:
+                name_string = f"{bold}{red}File {yellow}{key}{red}"
+                rule_violated_string = f"violates rule {yellow}#{error[1]}{red} of the MISRA C 2012 standard"
+                line_number_string = f"at line {yellow}{error[0]}{end}"
 
-def prettyprint(errors):
-    '''
-    Prettyprints the contents of the error dictionary with colors and stuff
-    '''
-    print("\033[1m\033[91m=================================================\n")
-    print("\033[1m       Static analysis results: Error Summary        \n")
-    for key in errors:
-        for error in errors[key]:
-            print("\033[1mFile \033[93m{0}\033[91m violates rule \033[93m#{1}\033[91m of the MISRA C 2012 standard at line \033[93m{2}\033[91m".format(key, error[1], error[0]))
-    print ""
-    print ""
-    print("\033[1m=================================================\033[0m\n")
+                print(f"{name_string.ljust(75)} {rule_violated_string} {line_number_string}")
 
+        print("")
+        print("")
+        print(bold + red +"=================================================" + end)
 
-def run():
-    errors = analyze()
+
+if __name__ == "__main__":
+    s = Summarizer(argv[1])
+    errors = s.analyze()
     if isinstance(errors, dict):
-        prettyprint(errors)
+        s.pretty_print(errors)
         exit(127)
     elif isinstance(errors, int) and errors == 0:
         exit(0)
-
-
-if __name__ == "__main__":
-    run()