-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expand mypy static type checking #32591
Expand mypy static type checking #32591
Conversation
Thanks for the pull request, @bradenmacdonald! As a core committer in this repo, you can merge this once the pull request is approved per the core committer reviewer requirements and according to the agreement with your edX Champion. |
63f73da
to
fb1c5f6
Compare
ADMIN_LEVEL = ContentLibraryPermission.ADMIN_LEVEL | ||
AUTHOR_LEVEL = ContentLibraryPermission.AUTHOR_LEVEL | ||
READ_LEVEL = ContentLibraryPermission.READ_LEVEL | ||
NO_ACCESS = None |
There was a problem hiding this comment.
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.
fb1c5f6
to
c1a889f
Compare
@@ -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]) |
There was a problem hiding this comment.
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.
edx-platform/openedx/core/djangoapps/content/learning_sequences/tests/test_views.py
Line 55 in 478c301
entrance_exam_id=None, |
@@ -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 |
There was a problem hiding this comment.
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.
@@ -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: |
There was a problem hiding this comment.
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 :/
@@ -49,7 +49,7 @@ def remove_large_data(fd: StagedContentFileData): | |||
""" Remove 'data' from the immutable StagedContentFileData object, if it's above the size limit """ | |||
if fd.data and len(fd.data) > limit: | |||
# these data objects are immutable so make a copy with data=None: | |||
return StagedContentFileData(**{**asdict(fd), "data": None}) | |||
return StagedContentFileData(**{**asdict(fd), "data": None}) # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why it didn't like this line, but I'm planning to remove this filter implementation soon anyways. So just ignored it for now.
@@ -182,16 +182,16 @@ def _save_static_assets_to_clipboard( | |||
Helper method for "post to clipboard" API endpoint. This deals with copying static files into the clipboard. | |||
""" | |||
files_to_save: list[StagedContentFileData] = [] | |||
for f in static_files: | |||
for sf in static_files: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to rename this variable because the f
used as an iterator in this for loop is considered the same as the f
used as the iterator in the second for loop in this function. I don't like how python does scoping.
80bc094
to
576f4d4
Compare
3761bf2
to
86cb4dd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
- I tested this: checked that the tests are passing
- I read through the code
- I checked for accessibility issues: n/a
- Includes documentation: n/a
- I made sure any change in configuration variables is reflected in the corresponding client's
configuration-secure
repository: n/a
@bradenmacdonald, I left a few suggestions, but none are blockers. Thanks for implementing this - I really like that we're adding more typing to Open edX! Btw. did you think about using pyright? We're running mypy only on a few packages in Open edX, so it could be nice to investigate it as an alternative. After doing this review, I ran it, and it detects more errors than mypy. E.g., it detects that this code can potentially raise pyright openedx/core/djangoapps/xblock/runtime/runtime.py
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:113:38 - error: Cannot access member "id" for type "User"
Member "id" is unknown (reportGeneralTypeIssues)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:143:49 - error: Cannot access member "get_site_root_url" for type "AppConfig"
Member "get_site_root_url" is unknown (reportGeneralTypeIssues)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:177:13 - error: Argument of type "int | str" cannot be assigned to parameter "__value" of type "str" in funct
ion "__setitem__"
Type "int | str" cannot be assigned to type "str"
"int" is incompatible with "str" (reportGeneralTypeIssues)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:178:9 - error: Argument of type "dict[Any, Any]" cannot be assigned to parameter "__value" of type "str" in f
unction "__setitem__"
"dict[Any, Any]" is incompatible with "str" (reportGeneralTypeIssues)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:187:26 - error: "is_anonymous" is not a known member of "None" (reportOptionalMemberAccess)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:244:21 - error: Argument of type "None" cannot be assigned to parameter "__value" of type "FieldData" in func
tion "__setitem__"
Type "None" cannot be assigned to type "FieldData" (reportGeneralTypeIssues)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:250:26 - error: "is_anonymous" is not a known member of "None" (reportOptionalMemberAccess)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:259:41 - error: "is_staff" is not a known member of "None" (reportOptionalMemberAccess)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:366:64 - error: Cannot access member "get_site_root_url" for type "AppConfig"
Member "get_site_root_url" is unknown (reportGeneralTypeIssues)
/edx/app/edxapp/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py:436:16 - error: Object of type "XBlockRuntime" is not callable (reportGeneralTypeIssues)
10 errors, 0 warnings, 0 informations |
@Agrendalath I thought about pyright and I tried it out, because it seems nicer and faster. But it doesn't have a plugin framework, so it doesn't support |
@bradenmacdonald, good point - I didn't think about Actually, the speed of both
For files =
lms,
openedx,
cms,
xmodule For [tool.pyright]
exclude = ['**/migrations', '**/__pycache__', '**/tests'] |
@Agrendalath Thanks, that seems doable. Another issue is Django though - while mypy has a plugin that works automatically together with django-stubs, for pyright you still have to add a lot of manual type annotations. https://github.com/sbdchd/django-types https://news.ycombinator.com/item?id=34223647 . Presumably same for DRF. I suspect that many of the issues pyright is flagging are due to it not understanding django as fully? |
@bradenmacdonald, you're right - We could try using |
86cb4dd
to
f485794
Compare
@bradenmacdonald 🎉 Your pull request was merged! Please take a moment to answer a two question survey so we can improve your experience in the future. |
2U Release Notice: This PR has been deployed to the edX staging environment in preparation for a release to production. |
2U Release Notice: This PR has been deployed to the edX production environment. |
1 similar comment
2U Release Notice: This PR has been deployed to the edX production environment. |
Description
The
edx-platform
codebase hasmypy
set up, but only a single django app (learning_sequences
) is currently type checked.This PR expands the type checking to include several django apps that I've developed:
openedx/core/djangoapps/content_staging
openedx/core/djangoapps/content_libraries
openedx/core/djangoapps/xblock
The type checking found a couple actual bugs in the code, which I have now fixed. It also required a bunch of additional tweaks here are there to get the type checks passing.
Testing instructions
MyPy tests should be run by CI, so just confirm that they ran.
Deadline
None
Other information
Private ref MNG-3784