From 0fc097d0a0e7a0ba8797c0a67eace4602b0355eb Mon Sep 17 00:00:00 2001
From: Dominik George <dominik.george@teckids.org>
Date: Wed, 21 Aug 2019 23:47:29 +0200
Subject: [PATCH] Add type hints. Closes #20.

---
 apps/official/BiscuIT-App-Alsijil         |  2 +-
 apps/official/BiscuIT-App-Chronos         |  2 +-
 apps/official/BiscuIT-App-Exlibris        |  2 +-
 apps/official/BiscuIT-App-SchILD-NRW      |  2 +-
 apps/official/BiscuIT-App-Untis           |  2 +-
 biscuit/core/apps.py                      |  4 ++--
 biscuit/core/decorators.py                |  3 ++-
 biscuit/core/mixins.py                    |  2 +-
 biscuit/core/models.py                    |  4 ++--
 biscuit/core/tables.py                    |  1 +
 biscuit/core/templatetags/data_helpers.py |  4 +++-
 biscuit/core/util/core_helpers.py         |  8 +++++---
 biscuit/core/util/messages.py             | 14 ++++++++------
 biscuit/core/util/sass_helpers.py         |  3 ++-
 biscuit/core/views.py                     | 20 ++++++++++++--------
 15 files changed, 43 insertions(+), 30 deletions(-)

diff --git a/apps/official/BiscuIT-App-Alsijil b/apps/official/BiscuIT-App-Alsijil
index a9df90013..7a51426bc 160000
--- a/apps/official/BiscuIT-App-Alsijil
+++ b/apps/official/BiscuIT-App-Alsijil
@@ -1 +1 @@
-Subproject commit a9df90013aa7330fc2917517f8859f35dc950ebb
+Subproject commit 7a51426bc1219837893af2766ce8c7f9fab296f2
diff --git a/apps/official/BiscuIT-App-Chronos b/apps/official/BiscuIT-App-Chronos
index 5e8efdcbb..e96f8a231 160000
--- a/apps/official/BiscuIT-App-Chronos
+++ b/apps/official/BiscuIT-App-Chronos
@@ -1 +1 @@
-Subproject commit 5e8efdcbb326e4b19ed58fd1d1b1e0d995e95882
+Subproject commit e96f8a231fe363b568a2809e92ddb54e83deceff
diff --git a/apps/official/BiscuIT-App-Exlibris b/apps/official/BiscuIT-App-Exlibris
index ad8af3fe1..86d3a0a2d 160000
--- a/apps/official/BiscuIT-App-Exlibris
+++ b/apps/official/BiscuIT-App-Exlibris
@@ -1 +1 @@
-Subproject commit ad8af3fe185217a5d95a7880d7d594089ad818b7
+Subproject commit 86d3a0a2d95541e1901e5dd372d46cfd9323a08d
diff --git a/apps/official/BiscuIT-App-SchILD-NRW b/apps/official/BiscuIT-App-SchILD-NRW
index ef6fed8b6..f2a41d5b4 160000
--- a/apps/official/BiscuIT-App-SchILD-NRW
+++ b/apps/official/BiscuIT-App-SchILD-NRW
@@ -1 +1 @@
-Subproject commit ef6fed8b6eb58bf855eba9828c248caeb9f94357
+Subproject commit f2a41d5b4e66aafc00d9a7487bb49c337a97049f
diff --git a/apps/official/BiscuIT-App-Untis b/apps/official/BiscuIT-App-Untis
index 50638fe23..0c78a36be 160000
--- a/apps/official/BiscuIT-App-Untis
+++ b/apps/official/BiscuIT-App-Untis
@@ -1 +1 @@
-Subproject commit 50638fe23de3f003e51460fd42604bd1f2e92764
+Subproject commit 0c78a36be79b6171c4c6d287387a0173ae513f2e
diff --git a/biscuit/core/apps.py b/biscuit/core/apps.py
index b2afdd550..844c9ad3e 100644
--- a/biscuit/core/apps.py
+++ b/biscuit/core/apps.py
@@ -10,7 +10,7 @@ class CoreConfig(AppConfig):
     name = 'biscuit.core'
     verbose_name = _('BiscuIT - The Free School Information System')
 
-    def clean_scss(self):
+    def clean_scss(self) -> None:
         for source_map in glob(os.path.join(settings.STATIC_ROOT, '*.css.map')):
             try:
                 os.unlink(source_map)
@@ -18,5 +18,5 @@ class CoreConfig(AppConfig):
                 # Ignore because old is better than nothing
                 pass  # noqa
 
-    def ready(self):
+    def ready(self) -> None:
         self.clean_scss()
diff --git a/biscuit/core/decorators.py b/biscuit/core/decorators.py
index 1881f2462..732f12095 100644
--- a/biscuit/core/decorators.py
+++ b/biscuit/core/decorators.py
@@ -1,7 +1,8 @@
+from typing import Callable
 from django.contrib.auth.decorators import user_passes_test
 
 
-def admin_required(function=None):
+def admin_required(function: Callable = None) -> Callable:
     actual_decorator = user_passes_test(
         lambda u: u.is_active and u.is_superuser)
     return actual_decorator(function)
diff --git a/biscuit/core/mixins.py b/biscuit/core/mixins.py
index f5fcc947b..3fa40c9b7 100644
--- a/biscuit/core/mixins.py
+++ b/biscuit/core/mixins.py
@@ -4,7 +4,7 @@ from .util.core_helpers import get_current_school
 
 
 class SchoolRelatedManager(models.Manager):
-    def get_queryset(self):
+    def get_queryset(self) -> models.query.QuerySet:
         qs = super().get_queryset()
         school = get_current_school()
 
diff --git a/biscuit/core/models.py b/biscuit/core/models.py
index 784215228..7839c0e6b 100644
--- a/biscuit/core/models.py
+++ b/biscuit/core/models.py
@@ -76,7 +76,7 @@ class Person(SchoolRelated):
 
     primary_group = models.ForeignKey('Group', models.SET_NULL, null=True)
 
-    def __str__(self):
+    def __str__(self) -> str:
         return '%s, %s' % (self.last_name, self.first_name)
 
 
@@ -96,5 +96,5 @@ class Group(SchoolRelated):
     members = models.ManyToManyField('Person', related_name='member_of')
     owners = models.ManyToManyField('Person', related_name='owner_of')
 
-    def __str__(self):
+    def __str__(self) -> str:
         return '%s (%s)' % (self.name, self.short_name)
diff --git a/biscuit/core/tables.py b/biscuit/core/tables.py
index f7fbeb93a..0b57e2b11 100644
--- a/biscuit/core/tables.py
+++ b/biscuit/core/tables.py
@@ -10,6 +10,7 @@ class PersonsTable(tables.Table):
     first_name = tables.LinkColumn('person_by_id', args=[A('id')])
     last_name = tables.LinkColumn('person_by_id', args=[A('id')])
 
+
 class GroupsTable(tables.Table):
     class Meta:
         attrs = {'class': 'table table-striped table-bordered table-hover table-responsive-xl'}
diff --git a/biscuit/core/templatetags/data_helpers.py b/biscuit/core/templatetags/data_helpers.py
index 8f28bcc95..f5fb6a56f 100644
--- a/biscuit/core/templatetags/data_helpers.py
+++ b/biscuit/core/templatetags/data_helpers.py
@@ -1,8 +1,10 @@
+from typing import Dict, Any
+
 from django import template
 
 register = template.Library()
 
 
 @register.filter
-def get_dict(value, arg):
+def get_dict(value: Dict[Any, Any], arg: Any) -> Any:
     return value[arg]
diff --git a/biscuit/core/util/core_helpers.py b/biscuit/core/util/core_helpers.py
index d4bb3e380..94ffde727 100644
--- a/biscuit/core/util/core_helpers.py
+++ b/biscuit/core/util/core_helpers.py
@@ -1,11 +1,13 @@
 from importlib import import_module
 import pkgutil
-from typing import Sequence
+from typing import Optional, Sequence
 
 from django_global_request.middleware import get_request
 
+from ..models import School
 
-def get_app_packages() -> Sequence:
+
+def get_app_packages() -> Sequence[str]:
     """ Find all packages within the biscuit.apps namespace. """
 
     # Import error are non-fatal here because probably simply no app is installed.
@@ -29,7 +31,7 @@ def get_app_packages() -> Sequence:
     return pkgs
 
 
-def get_current_school():
+def get_current_school() -> Optional[School]:
     request = get_request()
 
     if request:
diff --git a/biscuit/core/util/messages.py b/biscuit/core/util/messages.py
index 7a1b35e01..98a273b90 100644
--- a/biscuit/core/util/messages.py
+++ b/biscuit/core/util/messages.py
@@ -1,30 +1,32 @@
 import logging
+from typing import Optional
 
 from django.contrib import messages
+from django.http import HttpRequest
 
 
-def add_message(request, level, message, **kwargs):
+def add_message(request: Optional[HttpRequest], level: int, message: str, **kwargs) -> Any:
     if request:
         return messages.add_message(request, level, message, **kwargs)
     else:
         return logging.getLogger(__name__).log(level, message)
 
 
-def debug(request, message, **kwargs):
+def debug(request: Optional[HttpRequest], message: str, **kwargs) -> Any
     return add_message(request, messages.DEBUG, message, **kwargs)
 
 
-def info(request, message, **kwargs):
+def info(request: Optional[HttpRequest], message: str, **kwargs) -> Any
     return add_message(request, messages.INFO, message, **kwargs)
 
 
-def success(request, message, **kwargs):
+def success(request: Optional[HttpRequest], message: str, **kwargs) -> Any
     return add_message(request, messages.SUCCESS, message, **kwargs)
 
 
-def warning(request, message, **kwargs):
+def warning(request: Optional[HttpRequest], message: str, **kwargs) -> Any
     return add_message(request, messages.WARNING, message, **kwargs)
 
 
-def error(request, message, **kwargs):
+def error(request: Optional[HttpRequest], message: str, **kwargs) -> Any
     return add_message(request, messages.ERROR, message, **kwargs)
diff --git a/biscuit/core/util/sass_helpers.py b/biscuit/core/util/sass_helpers.py
index ed864d07f..aa28accf3 100644
--- a/biscuit/core/util/sass_helpers.py
+++ b/biscuit/core/util/sass_helpers.py
@@ -1,7 +1,8 @@
 from colour import web2hex
 from sass import SassColor
 
-def get_colour(html_colour):
+
+def get_colour(html_colour: str) -> SassColor:
     rgb = web2hex(html_colour, force_long=True)[1:]
     r, g, b = int(rgb[0:2], 16), int(rgb[2:4], 16), int(rgb[4:6], 16)
 
diff --git a/biscuit/core/views.py b/biscuit/core/views.py
index e56a0ddd4..b4a4d6635 100644
--- a/biscuit/core/views.py
+++ b/biscuit/core/views.py
@@ -1,6 +1,6 @@
 from django.contrib.auth.decorators import login_required
 from django.conf import settings
-from django.http import Http404
+from django.http import Http404, HttpRequest, HttpResponse
 from django.shortcuts import render
 from django_tables2 import RequestConfig
 from django.utils.translation import ugettext_lazy as _
@@ -8,12 +8,13 @@ from .models import Person, Group
 from .tables import PersonsTable, GroupsTable
 
 
-def index(request):
+def index(request: HttpRequest) -> HttpResponse:
     context = {}
     return render(request, 'core/index.html', context)
 
-def error_handler(status):
-    def real_handler(request, *args, **kwargs):
+
+def error_handler(status: int) -> Callable[..., HttpResponse]:
+    def real_handler(request: HttpRequest, *args, **kwargs) -> HttpResponse:
         context = {}
 
         context['status'] = status
@@ -29,8 +30,9 @@ def error_handler(status):
 
     return real_handler
 
+
 @login_required
-def persons(request):
+def persons(request: HttpRequest) -> HttpResponse:
     context = {}
 
     # Get all persons
@@ -45,7 +47,7 @@ def persons(request):
 
 
 @login_required
-def person(request, id_, template):
+def person(request: HttpRequest, id_: int, template: str) -> HttpResponse:
     context = {}
 
     # Get person and check access
@@ -67,8 +69,9 @@ def person(request, id_, template):
 
     return render(request, 'core/person_%s.html' % template, context)
 
+
 @login_required
-def group(request, id_, template):
+def group(request: HttpRequest, id_: int, template: str) -> HttpResponse:
     context = {}
 
     # Get group and check if it exist
@@ -93,8 +96,9 @@ def group(request, id_, template):
 
     return render(request, 'core/group_%s.html' % template, context)
 
+
 @login_required
-def groups(request):
+def groups(request: HttpRequest) -> HttpResponse:
     context = {}
 
     # Get all groups
-- 
GitLab