diff --git a/.github/workflows/unittest.yaml b/.github/workflows/unittest.yaml
index b6a7352..53f385a 100644
--- a/.github/workflows/unittest.yaml
+++ b/.github/workflows/unittest.yaml
@@ -11,7 +11,7 @@ jobs:
     strategy:
       matrix:
         os: [ubuntu-latest, macOS-latest, windows-latest]
-        py_ver: ["3.7", "3.8", "3.9"]
+        py_ver: ["3.7", "3.8", "3.9", "3.10", "3.11"]
       fail-fast: false
     runs-on: ${{ matrix.os }}
     steps:
diff --git a/hacksoc_org/__init__.py b/hacksoc_org/__init__.py
index 3677db8..f2cd04b 100644
--- a/hacksoc_org/__init__.py
+++ b/hacksoc_org/__init__.py
@@ -4,12 +4,21 @@
     This module contains the Flask and Jinja boilerplate, HackSoc-specific customisations for pages,
     and user convenience functionality for local testing.
 """
+import sys
+
+if sys.version_info < (3, 7):
+    print(
+        "Warning: you are using an older version of Python ("
+        + str(sys.version)
+        + ") that is not supported by HackSoc.org."
+    )
 
 
 import flask
 import yaml
 from os import path
 
+
 # flask app is constructed here
 app = flask.Flask(__name__, static_folder=None, template_folder=None)
 # these folders are defined in the Blueprint anyway
diff --git a/hacksoc_org/freeze.py b/hacksoc_org/freeze.py
index 7fdf536..c7b1e40 100644
--- a/hacksoc_org/freeze.py
+++ b/hacksoc_org/freeze.py
@@ -84,11 +84,7 @@ def get_redirect_page_routes() -> Generator[str, None, None]:
     Yields:
         Generator[str, None, None]: URL routes
     """
-    yield from [
-        "/newsletter.html",
-        "/slack.html",
-        "/discord.html"
-    ]
+    yield from ["/newsletter.html", "/slack.html", "/discord.html"]
 
 
 def freeze():
diff --git a/hacksoc_org/loaders.py b/hacksoc_org/loaders.py
index ac7a0eb..942c6d1 100644
--- a/hacksoc_org/loaders.py
+++ b/hacksoc_org/loaders.py
@@ -54,7 +54,7 @@ def get_source(
         filename = os.path.join(self.path, removesuffix(template, ".html.jinja2") + ".md")
 
         if os.path.exists(filename):
-            with open(filename, encoding='utf-8') as fd:
+            with open(filename, encoding="utf-8") as fd:
                 metadata, markdown = frontmatter.parse(fd.read())
                 assert isinstance(metadata, dict)
                 source = """
@@ -74,8 +74,9 @@ def get_source(
         else:
             raise TemplateNotFound(filename)
 
+
 class MarkdownNewsLoader(BaseLoader):
-    """Finds news articles written in Markdown and wrangles them into a Jinja template 
+    """Finds news articles written in Markdown and wrangles them into a Jinja template
     extending article.html.jinja2"""
 
     def __init__(self, searchpath: str, prefix_allow: Optional[str] = None) -> None:
@@ -118,7 +119,7 @@ def get_source(
 
         filename = os.path.join(self.searchpath, removesuffix(template, ".html.jinja2") + ".md")
         if os.path.exists(filename):
-            with open(filename, encoding='utf-8') as fd:
+            with open(filename, encoding="utf-8") as fd:
                 metadata, content = frontmatter.parse(fd.read())
                 # NB: readlines() returns a list of lines WITH \n at the end
 
@@ -141,4 +142,4 @@ def get_source(
             return (source, filename, None)
             # TODO: add 3rd tuple argument for autoreloading
         else:
-            raise TemplateNotFound(template)
\ No newline at end of file
+            raise TemplateNotFound(template)
diff --git a/hacksoc_org/serve.py b/hacksoc_org/serve.py
index ae7acfc..a01cb9d 100644
--- a/hacksoc_org/serve.py
+++ b/hacksoc_org/serve.py
@@ -16,5 +16,5 @@ def serve(basedir: str, port=5000):
     print(f"Serving {basedir} at http://127.0.0.1:{port}/ ...")
 
     handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory=basedir)
-    server = http.server.HTTPServer(('localhost', port), RequestHandlerClass=handler)
+    server = http.server.HTTPServer(("localhost", port), RequestHandlerClass=handler)
     server.serve_forever()