Skip to content

Commit

Permalink
feat: expand mypy static type checking (#32591)
Browse files Browse the repository at this point in the history
* chore: typing + fixes for content_staging
* chore: typing + fixes for learning_sequences
* chore: typing + fixes for content_libraries
* chore: typing + fixes for new XBlock runtime
* feat: type hinting more code with mypy
  • Loading branch information
bradenmacdonald authored Jul 19, 2023
1 parent 92b6840 commit 57420ed
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 70 deletions.
14 changes: 13 additions & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,16 @@ follow_imports = silent
ignore_missing_imports = True
allow_untyped_globals = True
exclude = tests
files = openedx/core/djangoapps/content/learning_sequences/,openedx/core/types
plugins =
mypy_django_plugin.main,
mypy_drf_plugin.main
files =
openedx/core/djangoapps/content/learning_sequences/,
openedx/core/djangoapps/content_staging,
openedx/core/djangoapps/content_libraries,
openedx/core/djangoapps/xblock,
openedx/core/types

[mypy.plugins.django-stubs]
# content_staging only works with CMS; others work with either, so we run mypy with CMS settings.
django_settings_module = "cms.envs.test"
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/content/learning_sequences/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def not_deprecated(self, _attribute, value):
course_visibility: CourseVisibility = attr.ib(validator=attr.validators.in_(CourseVisibility))

# Entrance Exam ID
entrance_exam_id = attr.ib(type=str)
entrance_exam_id = attr.ib(type=Optional[str])

def __attrs_post_init__(self):
"""Post-init hook that validates and inits the `sequences` field."""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Generated by Django 2.2.24 on 2021-07-07 18:34

# type: ignore
from django.db import migrations
from django.db.models import Count, Min

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def _determine_user(self, request, course_key: CourseKey) -> types.User:
# Just like in masquerading, set real_user so that the
# SafeSessions middleware can see that the user didn't
# change unexpectedly.
target_user.real_user = request.user
target_user.real_user = request.user # type: ignore
return target_user

_course_masquerade, user = setup_masquerade(request, course_key, has_staff_access)
Expand Down
8 changes: 0 additions & 8 deletions openedx/core/djangoapps/content_libraries/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,6 @@ class LibraryBundleLink:
opaque_key = attr.ib(type=LearningContextKey, default=None)


class AccessLevel: # lint-amnesty, pylint: disable=function-redefined
""" Enum defining library access levels/permissions """
ADMIN_LEVEL = ContentLibraryPermission.ADMIN_LEVEL
AUTHOR_LEVEL = ContentLibraryPermission.AUTHOR_LEVEL
READ_LEVEL = ContentLibraryPermission.READ_LEVEL
NO_ACCESS = None


# General APIs
# ============

Expand Down
4 changes: 2 additions & 2 deletions openedx/core/djangoapps/content_staging/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ class UserClipboardAdmin(admin.ModelAdmin):
search_fields = ('user__username', 'source_usage_key', 'content__display_name')
readonly_fields = ('source_context_key', 'get_source_context_title')

@admin.display(description='Content')
def content_link(self, obj):
""" Display the StagedContent object as a link """
url = reverse('admin:content_staging_stagedcontent_change', args=[obj.content.pk])
return format_html('<a href="{}">{}</a>', url, obj.content)
content_link.short_description = 'Content'

@admin.display(description='Source Context Title')
def get_source_context_title(self, obj):
return obj.get_source_context_title()
get_source_context_title.short_description = 'Source Context Title'
4 changes: 2 additions & 2 deletions openedx/core/djangoapps/content_staging/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def get_user_clipboard(user_id: int, only_ready: bool = True) -> UserClipboardDa
)


def get_user_clipboard_json(user_id: int, request: HttpRequest = None):
def get_user_clipboard_json(user_id: int, request: HttpRequest | None = None):
"""
Get the detailed status of the user's clipboard, in exactly the same format
as returned from the
Expand Down Expand Up @@ -88,7 +88,7 @@ def get_staged_content_static_files(staged_content_id: int) -> list[StagedConten
sc = _StagedContent.objects.get(pk=staged_content_id)

def str_to_key(source_key_str: str):
if not str:
if not source_key_str:
return None
try:
return AssetKey.from_string(source_key_str)
Expand Down
1 change: 1 addition & 0 deletions openedx/core/djangoapps/content_staging/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Models for content staging (and clipboard)
"""
from __future__ import annotations
import logging

from django.contrib.auth import get_user_model
Expand Down
2 changes: 1 addition & 1 deletion openedx/core/djangoapps/content_staging/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def _save_static_assets_to_clipboard(
content: bytes | None = f.data
md5_hash = "" # Unknown
if content:
md5_hash = hashlib.md5(f.data).hexdigest()
md5_hash = hashlib.md5(content).hexdigest()
# This asset came from the XBlock's filesystem, e.g. a video block's transcript file
source_key = usage_key
# Check if the asset file exists. It can be absent if an XBlock contains an invalid link.
Expand Down
7 changes: 3 additions & 4 deletions openedx/core/djangoapps/xblock/apps.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"""
Django app configuration for the XBlock Runtime django app
"""


from django.apps import AppConfig, apps
from django.conf import settings

from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from .data import StudentDataMode


class XBlockAppConfig(AppConfig):
Expand Down Expand Up @@ -53,7 +52,7 @@ def get_runtime_system_params(self):
editing XBlock content in the LMS
"""
return dict(
student_data_mode='persisted',
student_data_mode=StudentDataMode.Persisted,
)

def get_site_root_url(self):
Expand All @@ -77,7 +76,7 @@ def get_runtime_system_params(self):
editing XBlock content in Studio
"""
return dict(
student_data_mode='ephemeral',
student_data_mode=StudentDataMode.Ephemeral,
)

def get_site_root_url(self):
Expand Down
13 changes: 13 additions & 0 deletions openedx/core/djangoapps/xblock/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
Data structures for the XBlock Django app's python APIs
"""
from enum import Enum


class StudentDataMode(Enum):
"""
Is student data (like which answer was selected) persisted in the DB or just stored temporarily in the session?
Generally, the LMS uses persistence and Studio uses ephemeral data.
"""
Ephemeral = 'ephemeral'
Persisted = 'persisted'
Loading

0 comments on commit 57420ed

Please sign in to comment.