Skip to content

Commit

Permalink
feat: [FC-0074] add static type checking for documentation purposes (o…
Browse files Browse the repository at this point in the history
  • Loading branch information
mariajgrimaldi authored Feb 10, 2025
1 parent 0a62bcf commit d91543f
Show file tree
Hide file tree
Showing 15 changed files with 169 additions and 40 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ upgrade: ## update the requirements/*.txt files with the latest packages satisf

quality: ## check coding style with pycodestyle and pylint
pylint openedx_filters test_utils *.py
mypy
pycodestyle openedx_filters *.py
pydocstyle openedx_filters *.py
isort --check-only --diff --recursive test_utils openedx_filters *.py test_settings.py
Expand Down
9 changes: 9 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[mypy]
allow_untyped_globals = False
plugins =
mypy_django_plugin.main,
files =
openedx_filters

[mypy.plugins.django-stubs]
django_settings_module = "test_utils.test_settings"
2 changes: 1 addition & 1 deletion openedx_filters/course_authoring/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class LMSPageURLRequested(OpenEdxPublicFilter):
filter_type = "org.openedx.course_authoring.lms.page.url.requested.v1"

@classmethod
def run_filter(cls, url: str, org: str) -> tuple[str, str]:
def run_filter(cls, url: str, org: str) -> tuple[str | None, str | None]:
"""
Process the inputs using the configured pipeline steps to modify the URL of the page requested by the user.
Expand Down
13 changes: 11 additions & 2 deletions openedx_filters/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"""


from typing import Optional


class OpenEdxFilterException(Exception):
"""
Base exception for filters.
Expand All @@ -18,7 +21,13 @@ class OpenEdxFilterException(Exception):
exception.
"""

def __init__(self, message="", redirect_to=None, status_code=None, **kwargs):
def __init__(
self,
message: str = "",
redirect_to: str = "",
status_code: Optional[int] = None,
**kwargs
) -> None:
"""
Init method for OpenEdxFilterException.
Expand All @@ -31,7 +40,7 @@ def __init__(self, message="", redirect_to=None, status_code=None, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)

def __str__(self):
def __str__(self) -> str:
"""
Show string representation of OpenEdxFilterException using its message.
"""
Expand Down
54 changes: 34 additions & 20 deletions openedx_filters/learning/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def __init__(self, message: str, response: Optional[HttpResponse] = None) -> Non
super().__init__(message, response=response)

@classmethod
def run_filter(cls, context: dict, template_name: str) -> tuple[dict, str]:
def run_filter(cls, context: dict[str, Any], template_name: str) -> tuple[dict[str, Any] | None, str | None]:
"""
Process the input context and template_name using the configured pipeline steps to modify the account settings.
Expand Down Expand Up @@ -178,7 +178,7 @@ def run_filter(cls, form_data: QueryDict) -> QueryDict:
"""
sensitive_data = cls.extract_sensitive_data(form_data)
data = super().run_pipeline(form_data=form_data)
form_data = data.get("form_data")
form_data = data.get("form_data", QueryDict())
form_data.update(sensitive_data)
return form_data

Expand Down Expand Up @@ -276,7 +276,7 @@ class PreventEnrollment(OpenEdxFilterException):
"""

@classmethod
def run_filter(cls, user: Any, course_key: CourseKey, mode: str) -> tuple[Any, CourseKey, str]:
def run_filter(cls, user: Any, course_key: CourseKey, mode: str) -> tuple[Any, CourseKey | None, str | None]:
"""
Process the user, course_key, and mode using the configured pipeline steps to modify the enrollment process.
Expand Down Expand Up @@ -368,14 +368,14 @@ class PreventCertificateCreation(OpenEdxFilterException):

@classmethod
def run_filter( # pylint: disable=too-many-positional-arguments
cls: type,
cls,
user: Any,
course_key: CourseKey,
mode: str,
status: str,
grade: float,
generation_mode: str,
) -> tuple[Any, CourseKey, str, str, float, str]:
) -> tuple[Any, CourseKey | None, str | None, str | None, float | None, str | None]:
"""
Process the inputs using the configured pipeline steps to modify the certificate creation process.
Expand Down Expand Up @@ -502,7 +502,7 @@ def __init__(self, message: str, response: HttpResponse) -> None:
)

@classmethod
def run_filter(cls, context: dict, custom_template: Any) -> tuple[dict, Any]:
def run_filter(cls, context: dict, custom_template: Any) -> tuple[dict[str, Any] | None, Any]:
"""
Process the context and custom_template using the configured pipeline steps to modify the certificate rendering.
Expand Down Expand Up @@ -707,7 +707,7 @@ def __init__(self, message: str, response: HttpResponse) -> None:
)

@classmethod
def run_filter(cls, context: dict, template_name: str) -> tuple[dict, str]:
def run_filter(cls, context: dict[str, Any], template_name: str) -> tuple[dict[str, Any] | None, str | None]:
"""
Process the context and template_name using the configured pipeline steps to modify the course about rendering.
Expand Down Expand Up @@ -825,7 +825,7 @@ def __init__(self, message: str, response: Optional[HttpResponse] = None) -> Non
)

@classmethod
def run_filter(cls, context: dict, template_name: str) -> tuple[dict, str]:
def run_filter(cls, context: dict[str, Any], template_name: str) -> tuple[dict[str, Any] | None, str | None]:
"""
Process the context and template_name using the configured pipeline steps to modify the dashboard rendering.
Expand Down Expand Up @@ -870,7 +870,7 @@ class PreventChildBlockRender(OpenEdxFilterException):
"""

@classmethod
def run_filter(cls, block: Any, context: dict) -> tuple[Any, dict]:
def run_filter(cls, block: Any, context: dict[str, Any]) -> tuple[Any, dict[str, Any] | None]:
"""
Process the block and context using the configured pipeline steps to modify the rendering of a child block.
Expand Down Expand Up @@ -913,7 +913,7 @@ class PreventEnrollmentQuerysetRequest(OpenEdxFilterException):
"""

@classmethod
def run_filter(cls, enrollments: QuerySet) -> QuerySet:
def run_filter(cls, enrollments: QuerySet) -> QuerySet | None:
"""
Process the enrollments QuerySet using the configured pipeline steps to modify the course enrollment data.
Expand Down Expand Up @@ -977,7 +977,11 @@ def __init__(self, message: str, response: Optional[HttpResponse] = None):
super().__init__(message, response=response)

@classmethod
def run_filter(cls, context: dict, student_view_context: dict):
def run_filter(
cls,
context: dict[str, Any],
student_view_context: dict
) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
"""
Process the inputs using the configured pipeline steps to modify the rendering of an XBlock.
Expand Down Expand Up @@ -1022,7 +1026,13 @@ class PreventVerticalBlockRender(OpenEdxFilterException):
"""

@classmethod
def run_filter(cls, block: Any, fragment: Any, context: dict, view: str) -> tuple[Any, Any, dict, str]:
def run_filter(
cls,
block: Any,
fragment: Any,
context: dict[str, Any],
view: str
) -> tuple[Any, Any, dict[str, Any] | None, str | None]:
"""
Process the inputs using the configured pipeline steps to modify the rendering of a vertical block.
Expand Down Expand Up @@ -1063,7 +1073,7 @@ class CourseHomeUrlCreationStarted(OpenEdxPublicFilter):
filter_type = "org.openedx.learning.course.homepage.url.creation.started.v1"

@classmethod
def run_filter(cls, course_key: CourseKey, course_home_url: str) -> tuple[CourseKey, str]:
def run_filter(cls, course_key: CourseKey, course_home_url: str) -> tuple[CourseKey | None, str | None]:
"""
Process the course_key and course_home_url using the configured pipeline steps to modify the course home url.
Expand Down Expand Up @@ -1100,7 +1110,11 @@ class CourseEnrollmentAPIRenderStarted(OpenEdxPublicFilter):
filter_type = "org.openedx.learning.home.enrollment.api.rendered.v1"

@classmethod
def run_filter(cls, course_key: CourseKey, serialized_enrollment: dict) -> tuple[CourseKey, dict]:
def run_filter(
cls,
course_key: CourseKey,
serialized_enrollment: dict[str, Any]
) -> tuple[CourseKey | None, dict[str, Any] | None]:
"""
Process the inputs using the configured pipeline steps to modify the course enrollment data.
Expand Down Expand Up @@ -1137,7 +1151,7 @@ class CourseRunAPIRenderStarted(OpenEdxPublicFilter):
filter_type = "org.openedx.learning.home.courserun.api.rendered.started.v1"

@classmethod
def run_filter(cls, serialized_courserun: dict) -> dict:
def run_filter(cls, serialized_courserun: dict[str, Any]) -> dict[str, Any] | None:
"""
Process the serialized_courserun using the configured pipeline steps to modify the course run data.
Expand Down Expand Up @@ -1251,7 +1265,7 @@ def __init__(self, message: str, response: Optional[HttpResponse] = None):
)

@classmethod
def run_filter(cls, context: dict, template_name: str) -> tuple[dict, str]:
def run_filter(cls, context: dict[str, Any], template_name: str) -> tuple[dict[str, Any] | None, str | None]:
"""
Process the context and template_name using the configured pipeline steps to modify the instructor dashboard.
Expand Down Expand Up @@ -1309,7 +1323,7 @@ def __init__(
super().__init__(message, context=context, template_name=template_name)

@classmethod
def run_filter(cls, context: dict, template_name: str) -> tuple[dict, str]:
def run_filter(cls, context: dict[str, Any], template_name: str) -> tuple[dict[str, Any] | None, str | None]:
"""
Process the context and template_name using the configured pipeline steps to modify the submission view.
Expand Down Expand Up @@ -1346,7 +1360,7 @@ class IDVPageURLRequested(OpenEdxPublicFilter):
filter_type = "org.openedx.learning.idv.page.url.requested.v1"

@classmethod
def run_filter(cls, url: str) -> str:
def run_filter(cls, url: str) -> str | None:
"""
Process the URL using the configured pipeline steps to modify the ID verification page URL.
Expand Down Expand Up @@ -1380,7 +1394,7 @@ class CourseAboutPageURLRequested(OpenEdxPublicFilter):
filter_type = "org.openedx.learning.course_about.page.url.requested.v1"

@classmethod
def run_filter(cls, url: str, org: str) -> tuple[str, str]:
def run_filter(cls, url: str, org: str) -> tuple[str | None, str | None]:
"""
Process the URL and org using the configured pipeline steps to modify the course about page URL.
Expand Down Expand Up @@ -1418,7 +1432,7 @@ class ScheduleQuerySetRequested(OpenEdxPublicFilter):
filter_type = "org.openedx.learning.schedule.queryset.requested.v1"

@classmethod
def run_filter(cls, schedules: QuerySet) -> QuerySet:
def run_filter(cls, schedules: QuerySet) -> QuerySet | None:
"""
Process the schedules QuerySet using the configured pipeline steps to modify the schedules data.
Expand Down
3 changes: 2 additions & 1 deletion openedx_filters/learning/tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"""
from unittest.mock import Mock, patch

from ddt import data, ddt, unpack
# Ignore the type error for ddt import since it is not recognized by mypy.
from ddt import data, ddt, unpack # type: ignore
from django.test import TestCase

from openedx_filters.learning.filters import (
Expand Down
3 changes: 2 additions & 1 deletion openedx_filters/tests/test_tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"""
from unittest.mock import Mock, patch

import ddt
# Ignore the type error for ddt import since it is not recognized by mypy.
import ddt # type: ignore
from django.test import TestCase, override_settings

from openedx_filters import PipelineStep
Expand Down
15 changes: 9 additions & 6 deletions openedx_filters/tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Tooling necessary to use Open edX Filters.
"""
from logging import getLogger
from typing import Any

from django.conf import settings
from django.utils.module_loading import import_string
Expand All @@ -18,14 +19,14 @@ class OpenEdxPublicFilter:

filter_type = ""

def __repr__(self):
def __repr__(self) -> str:
"""
Represent OpenEdxPublicFilter as a string.
"""
return "<OpenEdxPublicFilter: {filter_type}>".format(filter_type=self.filter_type)

@classmethod
def get_steps_for_pipeline(cls, pipeline, fail_silently):
def get_steps_for_pipeline(cls, pipeline: list, fail_silently: bool = True) -> list[type]:
"""
Get pipeline objects from paths.
Expand Down Expand Up @@ -68,7 +69,7 @@ def get_steps_for_pipeline(cls, pipeline, fail_silently):
return step_list

@classmethod
def get_pipeline_configuration(cls):
def get_pipeline_configuration(cls) -> tuple[list[str], bool, dict[str, Any]]:
"""
Get pipeline configuration from filter settings.
Expand Down Expand Up @@ -101,7 +102,9 @@ def get_pipeline_configuration(cls):
"""
filter_config = cls.get_filter_config()

pipeline, fail_silently, extra_config = [], True, {}
pipeline: list = []
fail_silently: bool = True
extra_config: dict = {}

if not filter_config:
return pipeline, fail_silently, extra_config
Expand All @@ -123,7 +126,7 @@ def get_pipeline_configuration(cls):
return pipeline, fail_silently, extra_config

@classmethod
def get_filter_config(cls):
def get_filter_config(cls) -> dict[str, Any]:
"""
Get filters configuration from Django settings.
Expand Down Expand Up @@ -157,7 +160,7 @@ def get_filter_config(cls):
return filters_config.get(cls.filter_type, {})

@classmethod
def run_pipeline(cls, **kwargs):
def run_pipeline(cls, **kwargs: Any) -> dict[str, Any] | Any:
"""
Execute filters in order based on the pipeline configuration.
Expand Down
9 changes: 6 additions & 3 deletions openedx_filters/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
"""


from django.http import QueryDict


class SensitiveDataManagementMixin:
"""
Custom class used manage sensitive data within filter arguments.
"""

sensitive_form_data = []
sensitive_form_data: list[str] = []

@classmethod
def extract_sensitive_data(cls, form_data):
def extract_sensitive_data(cls, form_data: QueryDict) -> dict[str, str]:
"""
Extract sensitive data from its child class input arguments.
Expand All @@ -30,6 +33,6 @@ def extract_sensitive_data(cls, form_data):
for key, value in base_form_data.items():
if key in cls.sensitive_form_data:
form_data.pop(key)
sensitive_data[key] = value
sensitive_data[key] = str(value)

return sensitive_data
Loading

0 comments on commit d91543f

Please sign in to comment.