Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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])

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was unclear if this should be changed to allow None or if None values should be converted to "" when stored in this field, but there were clear examples if it being explicitly set to None in the tests, so I went with this.

https://github.com/openedx/edx-platform/blob/478c301df5ab0a58dad43cedfc05e4003828c2d3/openedx/core/djangoapps/content/learning_sequences/tests/test_views.py#L55


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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until python typing supports intersections there is no way to tell the type system that we want to add a real_user attribute onto the User class, so I just ignored this line.

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out this was defined twice in this file. The pylint warning was suppressed by an automatic lint amnesty line.



# 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:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a clear bug found by the type check. 🐛 str here was the global string type :/

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