Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
1febdbfa
Commit
1febdbfa
authored
Sep 23, 2017
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Grades cleanup: remove read_only param and create method
EDUCATOR-171
parent
649f3ccd
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
169 additions
and
191 deletions
+169
-191
common/djangoapps/student/views.py
+1
-1
lms/djangoapps/ccx/tests/test_field_override_performance.py
+27
-27
lms/djangoapps/ccx/tests/test_views.py
+3
-0
lms/djangoapps/ccx/utils.py
+0
-6
lms/djangoapps/ccx/views.py
+0
-3
lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py
+1
-1
lms/djangoapps/certificates/queue.py
+1
-1
lms/djangoapps/certificates/tests/test_queue.py
+1
-1
lms/djangoapps/courseware/tests/test_submitting_problems.py
+5
-27
lms/djangoapps/courseware/tests/test_views.py
+10
-11
lms/djangoapps/courseware/views/index.py
+1
-1
lms/djangoapps/courseware/views/views.py
+3
-5
lms/djangoapps/gating/tests/test_integration.py
+1
-1
lms/djangoapps/grades/api/tests/test_views.py
+7
-8
lms/djangoapps/grades/api/views.py
+1
-3
lms/djangoapps/grades/config/__init__.py
+8
-1
lms/djangoapps/grades/course_data.py
+3
-2
lms/djangoapps/grades/course_grade.py
+26
-4
lms/djangoapps/grades/course_grade_factory.py
+30
-48
lms/djangoapps/grades/signals/handlers.py
+2
-1
lms/djangoapps/grades/tests/test_grades.py
+2
-2
lms/djangoapps/grades/tests/test_new.py
+0
-0
lms/djangoapps/grades/tests/test_tasks.py
+4
-4
lms/djangoapps/grades/tests/utils.py
+12
-8
lms/djangoapps/instructor/tests/test_spoc_gradebook.py
+2
-0
lms/djangoapps/instructor/views/gradebook_api.py
+1
-1
lms/djangoapps/instructor_task/tests/test_integration.py
+1
-1
lms/djangoapps/instructor_task/tests/test_tasks_helper.py
+2
-2
lms/djangoapps/lti_provider/tasks.py
+1
-1
lms/djangoapps/lti_provider/tests/test_tasks.py
+1
-1
lms/djangoapps/shoppingcart/tests/test_models.py
+6
-18
lms/envs/bok_choy.py
+5
-1
lms/envs/test.py
+1
-0
No files found.
common/djangoapps/student/views.py
View file @
1febdbfa
...
@@ -413,7 +413,7 @@ def _cert_info(user, course_overview, cert_status, course_mode): # pylint: disa
...
@@ -413,7 +413,7 @@ def _cert_info(user, course_overview, cert_status, course_mode): # pylint: disa
if
status
in
{
'generating'
,
'ready'
,
'notpassing'
,
'restricted'
,
'auditing'
,
'unverified'
}:
if
status
in
{
'generating'
,
'ready'
,
'notpassing'
,
'restricted'
,
'auditing'
,
'unverified'
}:
cert_grade_percent
=
-
1
cert_grade_percent
=
-
1
persisted_grade_percent
=
-
1
persisted_grade_percent
=
-
1
persisted_grade
=
CourseGradeFactory
()
.
read
(
user
,
course
=
course_overview
)
persisted_grade
=
CourseGradeFactory
()
.
read
(
user
,
course
=
course_overview
,
create_if_needed
=
False
)
if
persisted_grade
is
not
None
:
if
persisted_grade
is
not
None
:
persisted_grade_percent
=
persisted_grade
.
percent
persisted_grade_percent
=
persisted_grade
.
percent
...
...
lms/djangoapps/ccx/tests/test_field_override_performance.py
View file @
1febdbfa
...
@@ -237,18 +237,18 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase):
...
@@ -237,18 +237,18 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase):
# # of sql queries to default,
# # of sql queries to default,
# # of mongo queries,
# # of mongo queries,
# )
# )
(
'no_overrides'
,
1
,
True
,
False
):
(
26
,
1
),
(
'no_overrides'
,
1
,
True
,
False
):
(
19
,
1
),
(
'no_overrides'
,
2
,
True
,
False
):
(
26
,
1
),
(
'no_overrides'
,
2
,
True
,
False
):
(
19
,
1
),
(
'no_overrides'
,
3
,
True
,
False
):
(
26
,
1
),
(
'no_overrides'
,
3
,
True
,
False
):
(
19
,
1
),
(
'ccx'
,
1
,
True
,
False
):
(
26
,
1
),
(
'ccx'
,
1
,
True
,
False
):
(
19
,
1
),
(
'ccx'
,
2
,
True
,
False
):
(
26
,
1
),
(
'ccx'
,
2
,
True
,
False
):
(
19
,
1
),
(
'ccx'
,
3
,
True
,
False
):
(
26
,
1
),
(
'ccx'
,
3
,
True
,
False
):
(
19
,
1
),
(
'no_overrides'
,
1
,
False
,
False
):
(
26
,
1
),
(
'no_overrides'
,
1
,
False
,
False
):
(
19
,
1
),
(
'no_overrides'
,
2
,
False
,
False
):
(
26
,
1
),
(
'no_overrides'
,
2
,
False
,
False
):
(
19
,
1
),
(
'no_overrides'
,
3
,
False
,
False
):
(
26
,
1
),
(
'no_overrides'
,
3
,
False
,
False
):
(
19
,
1
),
(
'ccx'
,
1
,
False
,
False
):
(
26
,
1
),
(
'ccx'
,
1
,
False
,
False
):
(
19
,
1
),
(
'ccx'
,
2
,
False
,
False
):
(
26
,
1
),
(
'ccx'
,
2
,
False
,
False
):
(
19
,
1
),
(
'ccx'
,
3
,
False
,
False
):
(
26
,
1
),
(
'ccx'
,
3
,
False
,
False
):
(
19
,
1
),
}
}
...
@@ -260,19 +260,19 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase):
...
@@ -260,19 +260,19 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase):
__test__
=
True
__test__
=
True
TEST_DATA
=
{
TEST_DATA
=
{
(
'no_overrides'
,
1
,
True
,
False
):
(
26
,
3
),
(
'no_overrides'
,
1
,
True
,
False
):
(
19
,
3
),
(
'no_overrides'
,
2
,
True
,
False
):
(
26
,
3
),
(
'no_overrides'
,
2
,
True
,
False
):
(
19
,
3
),
(
'no_overrides'
,
3
,
True
,
False
):
(
26
,
3
),
(
'no_overrides'
,
3
,
True
,
False
):
(
19
,
3
),
(
'ccx'
,
1
,
True
,
False
):
(
26
,
3
),
(
'ccx'
,
1
,
True
,
False
):
(
19
,
3
),
(
'ccx'
,
2
,
True
,
False
):
(
26
,
3
),
(
'ccx'
,
2
,
True
,
False
):
(
19
,
3
),
(
'ccx'
,
3
,
True
,
False
):
(
26
,
3
),
(
'ccx'
,
3
,
True
,
False
):
(
19
,
3
),
(
'ccx'
,
1
,
True
,
True
):
(
2
7
,
3
),
(
'ccx'
,
1
,
True
,
True
):
(
2
0
,
3
),
(
'ccx'
,
2
,
True
,
True
):
(
2
7
,
3
),
(
'ccx'
,
2
,
True
,
True
):
(
2
0
,
3
),
(
'ccx'
,
3
,
True
,
True
):
(
2
7
,
3
),
(
'ccx'
,
3
,
True
,
True
):
(
2
0
,
3
),
(
'no_overrides'
,
1
,
False
,
False
):
(
26
,
3
),
(
'no_overrides'
,
1
,
False
,
False
):
(
19
,
3
),
(
'no_overrides'
,
2
,
False
,
False
):
(
26
,
3
),
(
'no_overrides'
,
2
,
False
,
False
):
(
19
,
3
),
(
'no_overrides'
,
3
,
False
,
False
):
(
26
,
3
),
(
'no_overrides'
,
3
,
False
,
False
):
(
19
,
3
),
(
'ccx'
,
1
,
False
,
False
):
(
26
,
3
),
(
'ccx'
,
1
,
False
,
False
):
(
19
,
3
),
(
'ccx'
,
2
,
False
,
False
):
(
26
,
3
),
(
'ccx'
,
2
,
False
,
False
):
(
19
,
3
),
(
'ccx'
,
3
,
False
,
False
):
(
26
,
3
),
(
'ccx'
,
3
,
False
,
False
):
(
19
,
3
),
}
}
lms/djangoapps/ccx/tests/test_views.py
View file @
1febdbfa
...
@@ -36,6 +36,7 @@ from lms.djangoapps.ccx.tests.factories import CcxFactory
...
@@ -36,6 +36,7 @@ from lms.djangoapps.ccx.tests.factories import CcxFactory
from
lms.djangoapps.ccx.tests.utils
import
CcxTestCase
,
flatten
from
lms.djangoapps.ccx.tests.utils
import
CcxTestCase
,
flatten
from
lms.djangoapps.ccx.utils
import
ccx_course
,
is_email
from
lms.djangoapps.ccx.utils
import
ccx_course
,
is_email
from
lms.djangoapps.ccx.views
import
get_date
from
lms.djangoapps.ccx.views
import
get_date
from
lms.djangoapps.grades.tasks
import
compute_all_grades_for_course
from
lms.djangoapps.instructor.access
import
allow_access
,
list_with_level
from
lms.djangoapps.instructor.access
import
allow_access
,
list_with_level
from
request_cache.middleware
import
RequestCache
from
request_cache.middleware
import
RequestCache
from
student.models
import
CourseEnrollment
,
CourseEnrollmentAllowed
from
student.models
import
CourseEnrollment
,
CourseEnrollmentAllowed
...
@@ -110,6 +111,8 @@ def setup_students_and_grades(context):
...
@@ -110,6 +111,8 @@ def setup_students_and_grades(context):
module_state_key
=
problem
.
location
module_state_key
=
problem
.
location
)
)
compute_all_grades_for_course
.
apply_async
(
kwargs
=
{
'course_key'
:
unicode
(
context
.
course
.
id
)})
def
unhide
(
unit
):
def
unhide
(
unit
):
"""
"""
...
...
lms/djangoapps/ccx/utils.py
View file @
1febdbfa
...
@@ -265,12 +265,6 @@ def ccx_students_enrolling_center(action, identifiers, email_students, course_ke
...
@@ -265,12 +265,6 @@ def ccx_students_enrolling_center(action, identifiers, email_students, course_ke
return
errors
return
errors
def
prep_course_for_grading
(
course
,
request
):
"""Set up course module for overrides to function properly"""
course
.
_field_data_cache
=
{}
# pylint: disable=protected-access
course
.
set_grading_policy
(
course
.
grading_policy
)
@contextmanager
@contextmanager
def
ccx_course
(
ccx_locator
):
def
ccx_course
(
ccx_locator
):
"""Create a context in which the course identified by course_locator exists
"""Create a context in which the course identified by course_locator exists
...
...
lms/djangoapps/ccx/views.py
View file @
1febdbfa
...
@@ -46,7 +46,6 @@ from lms.djangoapps.ccx.utils import (
...
@@ -46,7 +46,6 @@ from lms.djangoapps.ccx.utils import (
get_ccx_for_coach
,
get_ccx_for_coach
,
get_date
,
get_date
,
parse_date
,
parse_date
,
prep_course_for_grading
)
)
from
lms.djangoapps.grades.course_grade_factory
import
CourseGradeFactory
from
lms.djangoapps.grades.course_grade_factory
import
CourseGradeFactory
from
lms.djangoapps.instructor.enrollment
import
enroll_email
,
get_email_params
from
lms.djangoapps.instructor.enrollment
import
enroll_email
,
get_email_params
...
@@ -519,7 +518,6 @@ def ccx_gradebook(request, course, ccx=None):
...
@@ -519,7 +518,6 @@ def ccx_gradebook(request, course, ccx=None):
ccx_key
=
CCXLocator
.
from_course_locator
(
course
.
id
,
unicode
(
ccx
.
id
))
ccx_key
=
CCXLocator
.
from_course_locator
(
course
.
id
,
unicode
(
ccx
.
id
))
with
ccx_course
(
ccx_key
)
as
course
:
with
ccx_course
(
ccx_key
)
as
course
:
prep_course_for_grading
(
course
,
request
)
student_info
,
page
=
get_grade_book_page
(
request
,
course
,
course_key
=
ccx_key
)
student_info
,
page
=
get_grade_book_page
(
request
,
course
,
course_key
=
ccx_key
)
return
render_to_response
(
'courseware/gradebook.html'
,
{
return
render_to_response
(
'courseware/gradebook.html'
,
{
...
@@ -547,7 +545,6 @@ def ccx_grades_csv(request, course, ccx=None):
...
@@ -547,7 +545,6 @@ def ccx_grades_csv(request, course, ccx=None):
ccx_key
=
CCXLocator
.
from_course_locator
(
course
.
id
,
unicode
(
ccx
.
id
))
ccx_key
=
CCXLocator
.
from_course_locator
(
course
.
id
,
unicode
(
ccx
.
id
))
with
ccx_course
(
ccx_key
)
as
course
:
with
ccx_course
(
ccx_key
)
as
course
:
prep_course_for_grading
(
course
,
request
)
enrolled_students
=
User
.
objects
.
filter
(
enrolled_students
=
User
.
objects
.
filter
(
courseenrollment__course_id
=
ccx_key
,
courseenrollment__course_id
=
ccx_key
,
...
...
lms/djangoapps/certificates/management/commands/fix_ungraded_certs.py
View file @
1febdbfa
...
@@ -51,7 +51,7 @@ class Command(BaseCommand):
...
@@ -51,7 +51,7 @@ class Command(BaseCommand):
course
=
courses
.
get_course_by_id
(
course_id
)
course
=
courses
.
get_course_by_id
(
course_id
)
for
cert
in
ungraded
:
for
cert
in
ungraded
:
# grade the student
# grade the student
grade
=
CourseGradeFactory
()
.
create
(
cert
.
user
,
course
)
grade
=
CourseGradeFactory
()
.
read
(
cert
.
user
,
course
)
log
.
info
(
'grading
%
s -
%
s'
,
cert
.
user
,
grade
.
percent
)
log
.
info
(
'grading
%
s -
%
s'
,
cert
.
user
,
grade
.
percent
)
cert
.
grade
=
grade
.
percent
cert
.
grade
=
grade
.
percent
if
not
options
[
'noop'
]:
if
not
options
[
'noop'
]:
...
...
lms/djangoapps/certificates/queue.py
View file @
1febdbfa
...
@@ -269,7 +269,7 @@ class XQueueCertInterface(object):
...
@@ -269,7 +269,7 @@ class XQueueCertInterface(object):
self
.
request
.
session
=
{}
self
.
request
.
session
=
{}
is_whitelisted
=
self
.
whitelist
.
filter
(
user
=
student
,
course_id
=
course_id
,
whitelist
=
True
)
.
exists
()
is_whitelisted
=
self
.
whitelist
.
filter
(
user
=
student
,
course_id
=
course_id
,
whitelist
=
True
)
.
exists
()
course_grade
=
CourseGradeFactory
()
.
create
(
student
,
course
)
course_grade
=
CourseGradeFactory
()
.
read
(
student
,
course
)
enrollment_mode
,
__
=
CourseEnrollment
.
enrollment_mode_for_user
(
student
,
course_id
)
enrollment_mode
,
__
=
CourseEnrollment
.
enrollment_mode_for_user
(
student
,
course_id
)
mode_is_verified
=
enrollment_mode
in
GeneratedCertificate
.
VERIFIED_CERTS_MODES
mode_is_verified
=
enrollment_mode
in
GeneratedCertificate
.
VERIFIED_CERTS_MODES
user_is_verified
=
SoftwareSecurePhotoVerification
.
user_is_verified
(
student
)
user_is_verified
=
SoftwareSecurePhotoVerification
.
user_is_verified
(
student
)
...
...
lms/djangoapps/certificates/tests/test_queue.py
View file @
1febdbfa
...
@@ -265,7 +265,7 @@ class XQueueCertInterfaceAddCertificateTest(ModuleStoreTestCase):
...
@@ -265,7 +265,7 @@ class XQueueCertInterfaceAddCertificateTest(ModuleStoreTestCase):
)
)
# Run grading/cert generation again
# Run grading/cert generation again
with
mock_passing_grade
(
grade_pass
=
grade
):
with
mock_passing_grade
(
letter_grade
=
grade
):
with
patch
.
object
(
XQueueInterface
,
'send_to_queue'
)
as
mock_send
:
with
patch
.
object
(
XQueueInterface
,
'send_to_queue'
)
as
mock_send
:
mock_send
.
return_value
=
(
0
,
None
)
mock_send
.
return_value
=
(
0
,
None
)
self
.
xqueue
.
add_cert
(
self
.
user_2
,
self
.
course
.
id
)
self
.
xqueue
.
add_cert
(
self
.
user_2
,
self
.
course
.
id
)
...
...
lms/djangoapps/courseware/tests/test_submitting_problems.py
View file @
1febdbfa
...
@@ -29,6 +29,7 @@ from course_modes.models import CourseMode
...
@@ -29,6 +29,7 @@ from course_modes.models import CourseMode
from
courseware.models
import
BaseStudentModuleHistory
,
StudentModule
from
courseware.models
import
BaseStudentModuleHistory
,
StudentModule
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
courseware.tests.helpers
import
LoginEnrollmentTestCase
from
lms.djangoapps.grades.course_grade_factory
import
CourseGradeFactory
from
lms.djangoapps.grades.course_grade_factory
import
CourseGradeFactory
from
lms.djangoapps.grades.tasks
import
compute_all_grades_for_course
from
openedx.core.djangoapps.credit.api
import
get_credit_requirement_status
,
set_credit_requirements
from
openedx.core.djangoapps.credit.api
import
get_credit_requirement_status
,
set_credit_requirements
from
openedx.core.djangoapps.credit.models
import
CreditCourse
,
CreditProvider
from
openedx.core.djangoapps.credit.models
import
CreditCourse
,
CreditProvider
from
openedx.core.djangoapps.user_api.tests.factories
import
UserCourseTagFactory
from
openedx.core.djangoapps.user_api.tests.factories
import
UserCourseTagFactory
...
@@ -143,6 +144,7 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
...
@@ -143,6 +144,7 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
COURSE_NAME
=
"test_course"
COURSE_NAME
=
"test_course"
ENABLED_CACHES
=
[
'default'
,
'mongo_metadata_inheritance'
,
'loc_cache'
]
ENABLED_CACHES
=
[
'default'
,
'mongo_metadata_inheritance'
,
'loc_cache'
]
ENABLED_SIGNALS
=
[
'course_published'
]
def
setUp
(
self
):
def
setUp
(
self
):
super
(
TestSubmittingProblems
,
self
)
.
setUp
()
super
(
TestSubmittingProblems
,
self
)
.
setUp
()
...
@@ -156,25 +158,6 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
...
@@ -156,25 +158,6 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
self
.
enroll
(
self
.
course
)
self
.
enroll
(
self
.
course
)
self
.
student_user
=
User
.
objects
.
get
(
email
=
self
.
student
)
self
.
student_user
=
User
.
objects
.
get
(
email
=
self
.
student
)
self
.
factory
=
RequestFactory
()
self
.
factory
=
RequestFactory
()
# Disable the score change signal to prevent other components from being pulled into tests.
self
.
score_changed_signal_patch
=
patch
(
'lms.djangoapps.grades.signals.handlers.PROBLEM_WEIGHTED_SCORE_CHANGED.send'
)
self
.
score_changed_signal_patch
.
start
()
def
tearDown
(
self
):
super
(
TestSubmittingProblems
,
self
)
.
tearDown
()
self
.
_stop_signal_patch
()
def
_stop_signal_patch
(
self
):
"""
Stops the signal patch for the PROBLEM_WEIGHTED_SCORE_CHANGED event.
In case a test wants to test with the event actually
firing.
"""
if
self
.
score_changed_signal_patch
:
self
.
score_changed_signal_patch
.
stop
()
self
.
score_changed_signal_patch
=
None
def
add_dropdown_to_section
(
self
,
section_location
,
name
,
num_inputs
=
2
):
def
add_dropdown_to_section
(
self
,
section_location
,
name
,
num_inputs
=
2
):
"""
"""
...
@@ -278,7 +261,7 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
...
@@ -278,7 +261,7 @@ class TestSubmittingProblems(ModuleStoreTestCase, LoginEnrollmentTestCase, Probl
"""
"""
Return CourseGrade for current user and course.
Return CourseGrade for current user and course.
"""
"""
return
CourseGradeFactory
()
.
create
(
self
.
student_user
,
self
.
course
)
return
CourseGradeFactory
()
.
read
(
self
.
student_user
,
self
.
course
)
def
check_grade_percent
(
self
,
percent
):
def
check_grade_percent
(
self
,
percent
):
"""
"""
...
@@ -424,6 +407,7 @@ class TestCourseGrader(TestSubmittingProblems):
...
@@ -424,6 +407,7 @@ class TestCourseGrader(TestSubmittingProblems):
]
]
}
}
self
.
add_grading_policy
(
grading_policy
)
self
.
add_grading_policy
(
grading_policy
)
compute_all_grades_for_course
.
apply_async
(
kwargs
=
{
'course_key'
:
unicode
(
self
.
course
.
id
)})
def
dropping_setup
(
self
):
def
dropping_setup
(
self
):
"""
"""
...
@@ -597,10 +581,6 @@ class TestCourseGrader(TestSubmittingProblems):
...
@@ -597,10 +581,6 @@ class TestCourseGrader(TestSubmittingProblems):
self
.
check_grade_percent
(
0.67
)
self
.
check_grade_percent
(
0.67
)
self
.
assertEqual
(
self
.
get_course_grade
()
.
letter_grade
,
'B'
)
self
.
assertEqual
(
self
.
get_course_grade
()
.
letter_grade
,
'B'
)
# But now, set the score with the submissions API and watch
# as it overrides the score read from StudentModule and our
# student gets an A instead.
self
.
_stop_signal_patch
()
student_item
=
{
student_item
=
{
'student_id'
:
anonymous_id_for_user
(
self
.
student_user
,
self
.
course
.
id
),
'student_id'
:
anonymous_id_for_user
(
self
.
student_user
,
self
.
course
.
id
),
'course_id'
:
unicode
(
self
.
course
.
id
),
'course_id'
:
unicode
(
self
.
course
.
id
),
...
@@ -619,7 +599,6 @@ class TestCourseGrader(TestSubmittingProblems):
...
@@ -619,7 +599,6 @@ class TestCourseGrader(TestSubmittingProblems):
self
.
basic_setup
()
self
.
basic_setup
()
self
.
submit_question_answer
(
'p1'
,
{
'2_1'
:
'Correct'
})
self
.
submit_question_answer
(
'p1'
,
{
'2_1'
:
'Correct'
})
self
.
submit_question_answer
(
'p2'
,
{
'2_1'
:
'Correct'
})
self
.
submit_question_answer
(
'p2'
,
{
'2_1'
:
'Correct'
})
self
.
submit_question_answer
(
'p3'
,
{
'2_1'
:
'Incorrect'
})
with
patch
(
'submissions.api.get_scores'
)
as
mock_get_scores
:
with
patch
(
'submissions.api.get_scores'
)
as
mock_get_scores
:
mock_get_scores
.
return_value
=
{
mock_get_scores
.
return_value
=
{
...
@@ -629,7 +608,7 @@ class TestCourseGrader(TestSubmittingProblems):
...
@@ -629,7 +608,7 @@ class TestCourseGrader(TestSubmittingProblems):
'created_at'
:
now
(),
'created_at'
:
now
(),
},
},
}
}
self
.
get_course_grade
(
)
self
.
submit_question_answer
(
'p3'
,
{
'2_1'
:
'Incorrect'
}
)
# Verify that the submissions API was sent an anonymized student ID
# Verify that the submissions API was sent an anonymized student ID
mock_get_scores
.
assert_called_with
(
mock_get_scores
.
assert_called_with
(
...
@@ -764,7 +743,6 @@ class TestCourseGrader(TestSubmittingProblems):
...
@@ -764,7 +743,6 @@ class TestCourseGrader(TestSubmittingProblems):
req_status
=
get_credit_requirement_status
(
self
.
course
.
id
,
self
.
student_user
.
username
,
'grade'
,
'grade'
)
req_status
=
get_credit_requirement_status
(
self
.
course
.
id
,
self
.
student_user
.
username
,
'grade'
,
'grade'
)
self
.
assertEqual
(
req_status
[
0
][
"status"
],
None
)
self
.
assertEqual
(
req_status
[
0
][
"status"
],
None
)
self
.
_stop_signal_patch
()
self
.
submit_question_answer
(
'p1'
,
{
'2_1'
:
'Correct'
})
self
.
submit_question_answer
(
'p1'
,
{
'2_1'
:
'Correct'
})
self
.
submit_question_answer
(
'p2'
,
{
'2_1'
:
'Correct'
})
self
.
submit_question_answer
(
'p2'
,
{
'2_1'
:
'Correct'
})
...
...
lms/djangoapps/courseware/tests/test_views.py
View file @
1febdbfa
...
@@ -42,8 +42,6 @@ from django.test.utils import override_settings
...
@@ -42,8 +42,6 @@ from django.test.utils import override_settings
from
lms.djangoapps.commerce.utils
import
EcommerceService
# pylint: disable=import-error
from
lms.djangoapps.commerce.utils
import
EcommerceService
# pylint: disable=import-error
from
lms.djangoapps.grades.config.waffle
import
waffle
as
grades_waffle
from
lms.djangoapps.grades.config.waffle
import
waffle
as
grades_waffle
from
lms.djangoapps.grades.config.waffle
import
ASSUME_ZERO_GRADE_IF_ABSENT
from
lms.djangoapps.grades.config.waffle
import
ASSUME_ZERO_GRADE_IF_ABSENT
from
lms.djangoapps.grades.course_grade_factory
import
CourseGradeFactory
from
lms.djangoapps.grades.tests.utils
import
mock_get_score
from
milestones.tests.utils
import
MilestonesTestCaseMixin
from
milestones.tests.utils
import
MilestonesTestCaseMixin
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.keys
import
CourseKey
from
opaque_keys.edx.locations
import
Location
from
opaque_keys.edx.locations
import
Location
...
@@ -1399,7 +1397,7 @@ class ProgressPageTests(ProgressPageBaseTests):
...
@@ -1399,7 +1397,7 @@ class ProgressPageTests(ProgressPageBaseTests):
self
.
course
.
save
()
self
.
course
.
save
()
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
...
@@ -1442,7 +1440,7 @@ class ProgressPageTests(ProgressPageBaseTests):
...
@@ -1442,7 +1440,7 @@ class ProgressPageTests(ProgressPageBaseTests):
# Enable certificate generation for this course
# Enable certificate generation for this course
certs_api
.
set_cert_generation_enabled
(
self
.
course
.
id
,
True
)
certs_api
.
set_cert_generation_enabled
(
self
.
course
.
id
,
True
)
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
...
@@ -1458,9 +1456,10 @@ class ProgressPageTests(ProgressPageBaseTests):
...
@@ -1458,9 +1456,10 @@ class ProgressPageTests(ProgressPageBaseTests):
"""Test that query counts remain the same for self-paced and instructor-paced courses."""
"""Test that query counts remain the same for self-paced and instructor-paced courses."""
SelfPacedConfiguration
(
enabled
=
self_paced_enabled
)
.
save
()
SelfPacedConfiguration
(
enabled
=
self_paced_enabled
)
.
save
()
self
.
setup_course
(
self_paced
=
self_paced
)
self
.
setup_course
(
self_paced
=
self_paced
)
with
self
.
assertNumQueries
(
43
,
table_blacklist
=
QUERY_COUNT_TABLE_BLACKLIST
),
check_mongo_calls
(
1
):
with
self
.
assertNumQueries
(
36
,
table_blacklist
=
QUERY_COUNT_TABLE_BLACKLIST
),
check_mongo_calls
(
1
):
self
.
_get_progress_page
()
self
.
_get_progress_page
()
@patch.dict
(
settings
.
FEATURES
,
{
'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS'
:
False
})
@ddt.data
(
@ddt.data
(
(
False
,
43
,
27
),
(
False
,
43
,
27
),
(
True
,
36
,
23
)
(
True
,
36
,
23
)
...
@@ -1504,7 +1503,7 @@ class ProgressPageTests(ProgressPageBaseTests):
...
@@ -1504,7 +1503,7 @@ class ProgressPageTests(ProgressPageBaseTests):
'lms.djangoapps.verify_student.models.SoftwareSecurePhotoVerification.user_is_verified'
'lms.djangoapps.verify_student.models.SoftwareSecurePhotoVerification.user_is_verified'
)
as
user_verify
:
)
as
user_verify
:
user_verify
.
return_value
=
user_verified
user_verify
.
return_value
=
user_verified
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summary
=
{
course_grade
.
summary
=
{
...
@@ -1548,7 +1547,7 @@ class ProgressPageTests(ProgressPageBaseTests):
...
@@ -1548,7 +1547,7 @@ class ProgressPageTests(ProgressPageBaseTests):
self
.
course
.
save
()
self
.
course
.
save
()
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
self
.
store
.
update_item
(
self
.
course
,
self
.
user
.
id
)
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summary
=
{
course_grade
.
summary
=
{
...
@@ -1568,7 +1567,7 @@ class ProgressPageTests(ProgressPageBaseTests):
...
@@ -1568,7 +1567,7 @@ class ProgressPageTests(ProgressPageBaseTests):
"http://www.example.com/certificate.pdf"
,
"honor"
"http://www.example.com/certificate.pdf"
,
"honor"
)
)
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
...
@@ -1586,7 +1585,7 @@ class ProgressPageTests(ProgressPageBaseTests):
...
@@ -1586,7 +1585,7 @@ class ProgressPageTests(ProgressPageBaseTests):
self
.
assertTrue
(
self
.
client
.
login
(
username
=
user
.
username
,
password
=
'test'
))
self
.
assertTrue
(
self
.
client
.
login
(
username
=
user
.
username
,
password
=
'test'
))
CourseEnrollmentFactory
(
user
=
user
,
course_id
=
self
.
course
.
id
,
mode
=
CourseMode
.
AUDIT
)
CourseEnrollmentFactory
(
user
=
user
,
course_id
=
self
.
course
.
id
,
mode
=
CourseMode
.
AUDIT
)
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
,
'section_breakdown'
:
[],
'grade_breakdown'
:
{}}
...
@@ -2090,7 +2089,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
...
@@ -2090,7 +2089,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
status
=
CertificateStatuses
.
generating
,
status
=
CertificateStatuses
.
generating
,
mode
=
'verified'
mode
=
'verified'
)
)
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}
course_grade
.
summary
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}
...
@@ -2111,7 +2110,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
...
@@ -2111,7 +2110,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
mode
=
'verified'
mode
=
'verified'
)
)
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
as
mock_create
:
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
as
mock_create
:
course_grade
=
mock_create
.
return_value
course_grade
=
mock_create
.
return_value
course_grade
.
passed
=
True
course_grade
.
passed
=
True
course_grade
.
summay
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}
course_grade
.
summay
=
{
'grade'
:
'Pass'
,
'percent'
:
0.75
}
...
...
lms/djangoapps/courseware/views/index.py
View file @
1febdbfa
...
@@ -425,7 +425,7 @@ class CoursewareIndex(View):
...
@@ -425,7 +425,7 @@ class CoursewareIndex(View):
if
course_has_entrance_exam
(
self
.
course
)
and
getattr
(
self
.
chapter
,
'is_entrance_exam'
,
False
):
if
course_has_entrance_exam
(
self
.
course
)
and
getattr
(
self
.
chapter
,
'is_entrance_exam'
,
False
):
courseware_context
[
'entrance_exam_passed'
]
=
user_has_passed_entrance_exam
(
self
.
effective_user
,
self
.
course
)
courseware_context
[
'entrance_exam_passed'
]
=
user_has_passed_entrance_exam
(
self
.
effective_user
,
self
.
course
)
courseware_context
[
'entrance_exam_current_score'
]
=
get_entrance_exam_score_ratio
(
courseware_context
[
'entrance_exam_current_score'
]
=
get_entrance_exam_score_ratio
(
CourseGradeFactory
()
.
create
(
self
.
effective_user
,
self
.
course
),
CourseGradeFactory
()
.
read
(
self
.
effective_user
,
self
.
course
),
get_entrance_exam_usage_key
(
self
.
course
),
get_entrance_exam_usage_key
(
self
.
course
),
)
)
...
...
lms/djangoapps/courseware/views/views.py
View file @
1febdbfa
...
@@ -60,7 +60,6 @@ from enrollment.api import add_enrollment
...
@@ -60,7 +60,6 @@ from enrollment.api import add_enrollment
from
eventtracking
import
tracker
from
eventtracking
import
tracker
from
ipware.ip
import
get_ip
from
ipware.ip
import
get_ip
from
lms.djangoapps.ccx.custom_exception
import
CCXLocatorValidationException
from
lms.djangoapps.ccx.custom_exception
import
CCXLocatorValidationException
from
lms.djangoapps.ccx.utils
import
prep_course_for_grading
from
lms.djangoapps.courseware.exceptions
import
CourseAccessRedirect
,
Redirect
from
lms.djangoapps.courseware.exceptions
import
CourseAccessRedirect
,
Redirect
from
lms.djangoapps.experiments.utils
import
get_experiment_user_metadata_context
from
lms.djangoapps.experiments.utils
import
get_experiment_user_metadata_context
from
lms.djangoapps.grades.course_grade_factory
import
CourseGradeFactory
from
lms.djangoapps.grades.course_grade_factory
import
CourseGradeFactory
...
@@ -922,12 +921,11 @@ def _progress(request, course_key, student_id):
...
@@ -922,12 +921,11 @@ def _progress(request, course_key, student_id):
if
request
.
user
.
id
!=
student
.
id
:
if
request
.
user
.
id
!=
student
.
id
:
# refetch the course as the assumed student
# refetch the course as the assumed student
course
=
get_course_with_access
(
student
,
'load'
,
course_key
,
check_if_enrolled
=
True
)
course
=
get_course_with_access
(
student
,
'load'
,
course_key
,
check_if_enrolled
=
True
)
prep_course_for_grading
(
course
,
request
)
# NOTE: To make sure impersonation by instructor works, use
# NOTE: To make sure impersonation by instructor works, use
# student instead of request.user in the rest of the function.
# student instead of request.user in the rest of the function.
course_grade
=
CourseGradeFactory
()
.
create
(
student
,
course
)
course_grade
=
CourseGradeFactory
()
.
read
(
student
,
course
)
courseware_summary
=
course_grade
.
chapter_grades
.
values
()
courseware_summary
=
course_grade
.
chapter_grades
.
values
()
studio_url
=
get_studio_url
(
course
,
'settings/grading'
)
studio_url
=
get_studio_url
(
course
,
'settings/grading'
)
...
@@ -1015,7 +1013,7 @@ def _get_cert_data(student, course, enrollment_mode, course_grade=None):
...
@@ -1015,7 +1013,7 @@ def _get_cert_data(student, course, enrollment_mode, course_grade=None):
certificates_enabled_for_course
=
certs_api
.
cert_generation_enabled
(
course
.
id
)
certificates_enabled_for_course
=
certs_api
.
cert_generation_enabled
(
course
.
id
)
if
course_grade
is
None
:
if
course_grade
is
None
:
course_grade
=
CourseGradeFactory
()
.
create
(
student
,
course
)
course_grade
=
CourseGradeFactory
()
.
read
(
student
,
course
)
if
not
auto_certs_api
.
can_show_certificate_message
(
course
,
student
,
course_grade
,
certificates_enabled_for_course
):
if
not
auto_certs_api
.
can_show_certificate_message
(
course
,
student
,
course_grade
,
certificates_enabled_for_course
):
return
return
...
@@ -1290,7 +1288,7 @@ def is_course_passed(student, course, course_grade=None):
...
@@ -1290,7 +1288,7 @@ def is_course_passed(student, course, course_grade=None):
returns bool value
returns bool value
"""
"""
if
course_grade
is
None
:
if
course_grade
is
None
:
course_grade
=
CourseGradeFactory
()
.
create
(
student
,
course
)
course_grade
=
CourseGradeFactory
()
.
read
(
student
,
course
)
return
course_grade
.
passed
return
course_grade
.
passed
...
...
lms/djangoapps/gating/tests/test_integration.py
View file @
1febdbfa
...
@@ -149,7 +149,7 @@ class TestGatedContent(MilestonesTestCaseMixin, SharedModuleStoreTestCase):
...
@@ -149,7 +149,7 @@ class TestGatedContent(MilestonesTestCaseMixin, SharedModuleStoreTestCase):
all problems in the course, whether or not they are currently
all problems in the course, whether or not they are currently
gated.
gated.
"""
"""
course_grade
=
CourseGradeFactory
()
.
create
(
user
,
self
.
course
)
course_grade
=
CourseGradeFactory
()
.
read
(
user
,
self
.
course
)
for
prob
in
[
self
.
gating_prob1
,
self
.
gated_prob2
,
self
.
prob3
]:
for
prob
in
[
self
.
gating_prob1
,
self
.
gated_prob2
,
self
.
prob3
]:
self
.
assertIn
(
prob
.
location
,
course_grade
.
problem_scores
)
self
.
assertIn
(
prob
.
location
,
course_grade
.
problem_scores
)
...
...
lms/djangoapps/grades/api/tests/test_views.py
View file @
1febdbfa
...
@@ -15,7 +15,7 @@ from rest_framework.test import APITestCase
...
@@ -15,7 +15,7 @@ from rest_framework.test import APITestCase
from
capa.tests.response_xml_factory
import
MultipleChoiceResponseXMLFactory
from
capa.tests.response_xml_factory
import
MultipleChoiceResponseXMLFactory
from
lms.djangoapps.courseware.tests.factories
import
GlobalStaffFactory
,
StaffFactory
from
lms.djangoapps.courseware.tests.factories
import
GlobalStaffFactory
,
StaffFactory
from
lms.djangoapps.grades.tests.utils
import
mock_
get_scor
e
from
lms.djangoapps.grades.tests.utils
import
mock_
passing_grad
e
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
student.tests.factories
import
CourseEnrollmentFactory
,
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.tests.django_utils
import
TEST_DATA_SPLIT_MODULESTORE
,
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
TEST_DATA_SPLIT_MODULESTORE
,
SharedModuleStoreTestCase
...
@@ -149,7 +149,7 @@ class CurrentGradeViewTest(SharedModuleStoreTestCase, APITestCase):
...
@@ -149,7 +149,7 @@ class CurrentGradeViewTest(SharedModuleStoreTestCase, APITestCase):
"""
"""
Test that a user can successfully request her own grade.
Test that a user can successfully request her own grade.
"""
"""
with
check_mongo_calls
(
6
):
with
check_mongo_calls
(
3
):
resp
=
self
.
client
.
get
(
self
.
get_url
(
self
.
student
.
username
))
resp
=
self
.
client
.
get
(
self
.
get_url
(
self
.
student
.
username
))
self
.
assertEqual
(
resp
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
resp
.
status_code
,
status
.
HTTP_200_OK
)
...
@@ -286,22 +286,21 @@ class CurrentGradeViewTest(SharedModuleStoreTestCase, APITestCase):
...
@@ -286,22 +286,21 @@ class CurrentGradeViewTest(SharedModuleStoreTestCase, APITestCase):
self
.
assertEqual
(
resp
.
data
,
expected_data
)
# pylint: disable=no-member
self
.
assertEqual
(
resp
.
data
,
expected_data
)
# pylint: disable=no-member
@ddt.data
(
@ddt.data
(
(
(
2
,
5
),
{
'letter_grade'
:
None
,
'percent'
:
0.4
,
'passed'
:
False
}),
({
'letter_grade'
:
None
,
'percent'
:
0.4
,
'passed'
:
False
}),
(
(
5
,
5
),
{
'letter_grade'
:
'Pass'
,
'percent'
:
1
,
'passed'
:
True
}),
({
'letter_grade'
:
'Pass'
,
'percent'
:
1
,
'passed'
:
True
}),
)
)
@ddt.unpack
def
test_grade
(
self
,
grade
):
def
test_grade
(
self
,
grade
,
result
):
"""
"""
Test that the user gets her grade in case she answered tests with an insufficient score.
Test that the user gets her grade in case she answered tests with an insufficient score.
"""
"""
with
mock_
get_score
(
*
grade
):
with
mock_
passing_grade
(
letter_grade
=
grade
[
'letter_grade'
],
percent
=
grade
[
'percent'
]
):
resp
=
self
.
client
.
get
(
self
.
get_url
(
self
.
student
.
username
))
resp
=
self
.
client
.
get
(
self
.
get_url
(
self
.
student
.
username
))
self
.
assertEqual
(
resp
.
status_code
,
status
.
HTTP_200_OK
)
self
.
assertEqual
(
resp
.
status_code
,
status
.
HTTP_200_OK
)
expected_data
=
{
expected_data
=
{
'username'
:
self
.
student
.
username
,
'username'
:
self
.
student
.
username
,
'course_key'
:
str
(
self
.
course_key
),
'course_key'
:
str
(
self
.
course_key
),
}
}
expected_data
.
update
(
result
)
expected_data
.
update
(
grade
)
self
.
assertEqual
(
resp
.
data
,
[
expected_data
])
# pylint: disable=no-member
self
.
assertEqual
(
resp
.
data
,
[
expected_data
])
# pylint: disable=no-member
...
...
lms/djangoapps/grades/api/views.py
View file @
1febdbfa
...
@@ -11,7 +11,6 @@ from rest_framework.generics import GenericAPIView, ListAPIView
...
@@ -11,7 +11,6 @@ from rest_framework.generics import GenericAPIView, ListAPIView
from
rest_framework.response
import
Response
from
rest_framework.response
import
Response
from
courseware.access
import
has_access
from
courseware.access
import
has_access
from
lms.djangoapps.ccx.utils
import
prep_course_for_grading
from
lms.djangoapps.courseware
import
courses
from
lms.djangoapps.courseware
import
courses
from
lms.djangoapps.courseware.exceptions
import
CourseAccessRedirect
from
lms.djangoapps.courseware.exceptions
import
CourseAccessRedirect
from
lms.djangoapps.grades.api.serializers
import
GradingPolicySerializer
from
lms.djangoapps.grades.api.serializers
import
GradingPolicySerializer
...
@@ -184,8 +183,7 @@ class UserGradeView(GradeViewMixin, GenericAPIView):
...
@@ -184,8 +183,7 @@ class UserGradeView(GradeViewMixin, GenericAPIView):
# or a 404 if the requested user does not exist.
# or a 404 if the requested user does not exist.
return
grade_user
return
grade_user
prep_course_for_grading
(
course
,
request
)
course_grade
=
CourseGradeFactory
()
.
read
(
grade_user
,
course
)
course_grade
=
CourseGradeFactory
()
.
create
(
grade_user
,
course
)
return
Response
([{
return
Response
([{
'username'
:
grade_user
.
username
,
'username'
:
grade_user
.
username
,
'course_key'
:
course_id
,
'course_key'
:
course_id
,
...
...
lms/djangoapps/grades/config/__init__.py
View file @
1febdbfa
from
django.conf
import
settings
from
lms.djangoapps.grades.config.models
import
PersistentGradesEnabledFlag
from
lms.djangoapps.grades.config.models
import
PersistentGradesEnabledFlag
from
lms.djangoapps.grades.config.waffle
import
waffle
as
waffle_func
,
ASSUME_ZERO_GRADE_IF_ABSENT
from
lms.djangoapps.grades.config.waffle
import
waffle
as
waffle_func
,
ASSUME_ZERO_GRADE_IF_ABSENT
...
@@ -6,7 +8,12 @@ def assume_zero_if_absent(course_key):
...
@@ -6,7 +8,12 @@ def assume_zero_if_absent(course_key):
"""
"""
Returns whether an absent grade should be assumed to be zero.
Returns whether an absent grade should be assumed to be zero.
"""
"""
return
should_persist_grades
(
course_key
)
and
waffle_func
()
.
is_enabled
(
ASSUME_ZERO_GRADE_IF_ABSENT
)
return
(
should_persist_grades
(
course_key
)
and
(
settings
.
FEATURES
.
get
(
'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS'
)
or
waffle_func
()
.
is_enabled
(
ASSUME_ZERO_GRADE_IF_ABSENT
)
)
)
def
should_persist_grades
(
course_key
):
def
should_persist_grades
(
course_key
):
...
...
lms/djangoapps/grades/course_data.py
View file @
1febdbfa
...
@@ -92,8 +92,9 @@ class CourseData(object):
...
@@ -92,8 +92,9 @@ class CourseData(object):
def
edited_on
(
self
):
def
edited_on
(
self
):
# get course block from structure only; subtree_edited_on field on modulestore's course block isn't optimized.
# get course block from structure only; subtree_edited_on field on modulestore's course block isn't optimized.
structure
=
self
.
_effective_structure
structure
=
self
.
_effective_structure
course_block
=
structure
[
self
.
location
]
if
structure
:
return
getattr
(
course_block
,
'subtree_edited_on'
,
None
)
course_block
=
structure
[
self
.
location
]
return
getattr
(
course_block
,
'subtree_edited_on'
,
None
)
def
__unicode__
(
self
):
def
__unicode__
(
self
):
return
u'Course: course_key: {}'
.
format
(
self
.
course_key
)
return
u'Course: course_key: {}'
.
format
(
self
.
course_key
)
...
...
lms/djangoapps/grades/course_grade.py
View file @
1febdbfa
...
@@ -7,6 +7,7 @@ from collections import OrderedDict, defaultdict
...
@@ -7,6 +7,7 @@ from collections import OrderedDict, defaultdict
from
django.conf
import
settings
from
django.conf
import
settings
from
lazy
import
lazy
from
lazy
import
lazy
from
ccx_keys.locator
import
CCXLocator
from
xmodule
import
block_metadata_utils
from
xmodule
import
block_metadata_utils
from
.subsection_grade
import
ZeroSubsectionGrade
from
.subsection_grade
import
ZeroSubsectionGrade
...
@@ -21,7 +22,7 @@ class CourseGradeBase(object):
...
@@ -21,7 +22,7 @@ class CourseGradeBase(object):
"""
"""
Base class for Course Grades.
Base class for Course Grades.
"""
"""
def
__init__
(
self
,
user
,
course_data
,
percent
=
0
,
letter_grade
=
None
,
passed
=
False
,
force_update_subsections
=
False
):
def
__init__
(
self
,
user
,
course_data
,
percent
=
0
.0
,
letter_grade
=
None
,
passed
=
False
,
force_update_subsections
=
False
):
self
.
user
=
user
self
.
user
=
user
self
.
course_data
=
course_data
self
.
course_data
=
course_data
...
@@ -137,8 +138,7 @@ class CourseGradeBase(object):
...
@@ -137,8 +138,7 @@ class CourseGradeBase(object):
"""
"""
Returns the result from the course grader.
Returns the result from the course grader.
"""
"""
course
=
self
.
course_data
.
course
course
=
self
.
_prep_course_for_grading
()
course
.
set_grading_policy
(
course
.
grading_policy
)
return
course
.
grader
.
grade
(
return
course
.
grader
.
grade
(
self
.
graded_subsections_by_format
,
self
.
graded_subsections_by_format
,
generate_random_scores
=
settings
.
GENERATE_PROFILE_SCORES
,
generate_random_scores
=
settings
.
GENERATE_PROFILE_SCORES
,
...
@@ -156,6 +156,27 @@ class CourseGradeBase(object):
...
@@ -156,6 +156,27 @@ class CourseGradeBase(object):
grade_summary
[
'grade'
]
=
self
.
letter_grade
grade_summary
[
'grade'
]
=
self
.
letter_grade
return
grade_summary
return
grade_summary
def
_prep_course_for_grading
(
self
):
"""
Make sure any overrides to the grading policy are used.
This is most relevant for CCX courses.
Right now, we still access the grading policy from the course
object. Once we get the grading policy from the BlockStructure
this will no longer be needed - since BlockStructure correctly
retrieves/uses all field overrides.
"""
course
=
self
.
course_data
.
course
if
isinstance
(
self
.
course_data
.
course_key
,
CCXLocator
):
# clean out any field values that may have been set from the
# parent course of the CCX course.
course
.
_field_data_cache
=
{}
# pylint: disable=protected-access
# this is "magic" code that automatically retrieves any overrides
# to the grading policy and updates the course object.
course
.
set_grading_policy
(
course
.
grading_policy
)
return
course
def
_get_chapter_grade_info
(
self
,
chapter
,
course_structure
):
def
_get_chapter_grade_info
(
self
,
chapter
,
course_structure
):
"""
"""
Helper that returns a dictionary of chapter grade information.
Helper that returns a dictionary of chapter grade information.
...
@@ -212,6 +233,7 @@ class CourseGrade(CourseGradeBase):
...
@@ -212,6 +233,7 @@ class CourseGrade(CourseGradeBase):
self
.
percent
=
self
.
_compute_percent
(
self
.
grader_result
)
self
.
percent
=
self
.
_compute_percent
(
self
.
grader_result
)
self
.
letter_grade
=
self
.
_compute_letter_grade
(
grade_cutoffs
,
self
.
percent
)
self
.
letter_grade
=
self
.
_compute_letter_grade
(
grade_cutoffs
,
self
.
percent
)
self
.
passed
=
self
.
_compute_passed
(
grade_cutoffs
,
self
.
percent
)
self
.
passed
=
self
.
_compute_passed
(
grade_cutoffs
,
self
.
percent
)
return
self
@lazy
@lazy
def
attempted
(
self
):
def
attempted
(
self
):
...
@@ -226,10 +248,10 @@ class CourseGrade(CourseGradeBase):
...
@@ -226,10 +248,10 @@ class CourseGrade(CourseGradeBase):
return
False
return
False
def
_get_subsection_grade
(
self
,
subsection
):
def
_get_subsection_grade
(
self
,
subsection
):
# Pass read_only here so the subsection grades can be persisted in bulk at the end.
if
self
.
force_update_subsections
:
if
self
.
force_update_subsections
:
return
self
.
_subsection_grade_factory
.
update
(
subsection
)
return
self
.
_subsection_grade_factory
.
update
(
subsection
)
else
:
else
:
# Pass read_only here so the subsection grades can be persisted in bulk at the end.
return
self
.
_subsection_grade_factory
.
create
(
subsection
,
read_only
=
True
)
return
self
.
_subsection_grade_factory
.
create
(
subsection
,
read_only
=
True
)
@staticmethod
@staticmethod
...
...
lms/djangoapps/grades/course_grade_factory.py
View file @
1febdbfa
...
@@ -20,48 +20,33 @@ class CourseGradeFactory(object):
...
@@ -20,48 +20,33 @@ class CourseGradeFactory(object):
"""
"""
GradeResult
=
namedtuple
(
'GradeResult'
,
[
'student'
,
'course_grade'
,
'error'
])
GradeResult
=
namedtuple
(
'GradeResult'
,
[
'student'
,
'course_grade'
,
'error'
])
def
create
(
self
,
user
,
course
=
None
,
collected_block_structure
=
None
,
course_structure
=
None
,
course_key
=
None
):
def
read
(
self
,
user
,
course
=
None
,
collected_block_structure
=
None
,
course_structure
=
None
,
course_key
=
None
,
create_if_needed
=
True
,
):
"""
"""
Returns the CourseGrade for the given user in the course.
Returns the CourseGrade for the given user in the course.
Reads the value from storage and validates that the grading
Reads the value from storage.
policy hasn't changed since the grade was last computed.
If not in storage, returns a ZeroGrade if ASSUME_ZERO_GRADE_IF_ABSENT.
If not in storage, returns a ZeroGrade if ASSUME_ZERO_GRADE_IF_ABSENT.
Else, if changed or not in storage, computes and returns a new value.
Else if create_if_needed, computes and returns a new value.
Else, returns None.
At least one of course, collected_block_structure, course_structure,
or course_key should be provided.
"""
course_data
=
CourseData
(
user
,
course
,
collected_block_structure
,
course_structure
,
course_key
)
try
:
course_grade
,
read_policy_hash
=
self
.
_read
(
user
,
course_data
)
if
read_policy_hash
==
course_data
.
grading_policy_hash
:
return
course_grade
read_only
=
False
# update the persisted grade since the policy changed; TODO(TNL-6786) remove soon
except
PersistentCourseGrade
.
DoesNotExist
:
if
assume_zero_if_absent
(
course_data
.
course_key
):
return
self
.
_create_zero
(
user
,
course_data
)
read_only
=
True
# keep the grade un-persisted; TODO(TNL-6786) remove once all grades are backfilled
return
self
.
_update
(
user
,
course_data
,
read_only
)
def
read
(
self
,
user
,
course
=
None
,
collected_block_structure
=
None
,
course_structure
=
None
,
course_key
=
None
):
"""
Returns the CourseGrade for the given user in the course as
persisted in storage. Does NOT verify whether the grading
policy is still valid since the grade was last computed.
If not in storage, returns a ZeroGrade if ASSUME_ZERO_GRADE_IF_ABSENT
else returns None.
At least one of course, collected_block_structure, course_structure,
At least one of course, collected_block_structure, course_structure,
or course_key should be provided.
or course_key should be provided.
"""
"""
course_data
=
CourseData
(
user
,
course
,
collected_block_structure
,
course_structure
,
course_key
)
course_data
=
CourseData
(
user
,
course
,
collected_block_structure
,
course_structure
,
course_key
)
try
:
try
:
course_grade
,
_
=
self
.
_read
(
user
,
course_data
)
return
self
.
_read
(
user
,
course_data
)
return
course_grade
except
PersistentCourseGrade
.
DoesNotExist
:
except
PersistentCourseGrade
.
DoesNotExist
:
if
assume_zero_if_absent
(
course_data
.
course_key
):
if
assume_zero_if_absent
(
course_data
.
course_key
):
return
self
.
_create_zero
(
user
,
course_data
)
return
self
.
_create_zero
(
user
,
course_data
)
elif
create_if_needed
:
return
self
.
_update
(
user
,
course_data
)
else
:
else
:
return
None
return
None
...
@@ -82,15 +67,7 @@ class CourseGradeFactory(object):
...
@@ -82,15 +67,7 @@ class CourseGradeFactory(object):
or course_key should be provided.
or course_key should be provided.
"""
"""
course_data
=
CourseData
(
user
,
course
,
collected_block_structure
,
course_structure
,
course_key
)
course_data
=
CourseData
(
user
,
course
,
collected_block_structure
,
course_structure
,
course_key
)
return
self
.
_update
(
user
,
course_data
,
read_only
=
False
,
force_update_subsections
=
force_update_subsections
)
return
self
.
_update
(
user
,
course_data
,
force_update_subsections
=
force_update_subsections
)
@contextmanager
def
_course_transaction
(
self
,
course_key
):
"""
Provides a transaction context in which GradeResults are created.
"""
yield
VisibleBlocks
.
clear_cache
(
course_key
)
def
iter
(
def
iter
(
self
,
self
,
...
@@ -123,6 +100,14 @@ class CourseGradeFactory(object):
...
@@ -123,6 +100,14 @@ class CourseGradeFactory(object):
with
dog_stats_api
.
timer
(
'lms.grades.CourseGradeFactory.iter'
,
tags
=
stats_tags
):
with
dog_stats_api
.
timer
(
'lms.grades.CourseGradeFactory.iter'
,
tags
=
stats_tags
):
yield
self
.
_iter_grade_result
(
user
,
course_data
,
force_update
)
yield
self
.
_iter_grade_result
(
user
,
course_data
,
force_update
)
@contextmanager
def
_course_transaction
(
self
,
course_key
):
"""
Provides a transaction context in which GradeResults are created.
"""
yield
VisibleBlocks
.
clear_cache
(
course_key
)
def
_iter_grade_result
(
self
,
user
,
course_data
,
force_update
):
def
_iter_grade_result
(
self
,
user
,
course_data
,
force_update
):
try
:
try
:
kwargs
=
{
kwargs
=
{
...
@@ -134,7 +119,7 @@ class CourseGradeFactory(object):
...
@@ -134,7 +119,7 @@ class CourseGradeFactory(object):
if
force_update
:
if
force_update
:
kwargs
[
'force_update_subsections'
]
=
True
kwargs
[
'force_update_subsections'
]
=
True
method
=
CourseGradeFactory
()
.
update
if
force_update
else
CourseGradeFactory
()
.
create
method
=
CourseGradeFactory
()
.
update
if
force_update
else
CourseGradeFactory
()
.
read
course_grade
=
method
(
**
kwargs
)
course_grade
=
method
(
**
kwargs
)
return
self
.
GradeResult
(
user
,
course_grade
,
None
)
return
self
.
GradeResult
(
user
,
course_grade
,
None
)
except
Exception
as
exc
:
# pylint: disable=broad-except
except
Exception
as
exc
:
# pylint: disable=broad-except
...
@@ -166,7 +151,9 @@ class CourseGradeFactory(object):
...
@@ -166,7 +151,9 @@ class CourseGradeFactory(object):
raise
PersistentCourseGrade
.
DoesNotExist
raise
PersistentCourseGrade
.
DoesNotExist
persistent_grade
=
PersistentCourseGrade
.
read
(
user
.
id
,
course_data
.
course_key
)
persistent_grade
=
PersistentCourseGrade
.
read
(
user
.
id
,
course_data
.
course_key
)
course_grade
=
CourseGrade
(
log
.
debug
(
u'Grades: Read,
%
s, User:
%
s,
%
s'
,
unicode
(
course_data
),
user
.
id
,
persistent_grade
)
return
CourseGrade
(
user
,
user
,
course_data
,
course_data
,
persistent_grade
.
percent_grade
,
persistent_grade
.
percent_grade
,
...
@@ -174,12 +161,8 @@ class CourseGradeFactory(object):
...
@@ -174,12 +161,8 @@ class CourseGradeFactory(object):
persistent_grade
.
passed_timestamp
is
not
None
,
persistent_grade
.
passed_timestamp
is
not
None
,
)
)
log
.
debug
(
u'Grades: Read,
%
s, User:
%
s,
%
s'
,
unicode
(
course_data
),
user
.
id
,
persistent_grade
)
return
course_grade
,
persistent_grade
.
grading_policy_hash
@staticmethod
@staticmethod
def
_update
(
user
,
course_data
,
read_only
,
force_update_subsections
=
False
):
def
_update
(
user
,
course_data
,
force_update_subsections
=
False
):
"""
"""
Computes, saves, and returns a CourseGrade object for the
Computes, saves, and returns a CourseGrade object for the
given user and course.
given user and course.
...
@@ -187,10 +170,9 @@ class CourseGradeFactory(object):
...
@@ -187,10 +170,9 @@ class CourseGradeFactory(object):
COURSE_GRADE_NOW_PASSED if learner has passed course.
COURSE_GRADE_NOW_PASSED if learner has passed course.
"""
"""
course_grade
=
CourseGrade
(
user
,
course_data
,
force_update_subsections
=
force_update_subsections
)
course_grade
=
CourseGrade
(
user
,
course_data
,
force_update_subsections
=
force_update_subsections
)
course_grade
.
update
()
course_grade
=
course_grade
.
update
()
should_persist
=
(
should_persist
=
(
(
not
read_only
)
and
# TODO(TNL-6786) Remove the read_only boolean once all grades are back-filled.
should_persist_grades
(
course_data
.
course_key
)
and
should_persist_grades
(
course_data
.
course_key
)
and
course_grade
.
attempted
course_grade
.
attempted
)
)
...
...
lms/djangoapps/grades/signals/handlers.py
View file @
1febdbfa
...
@@ -254,7 +254,8 @@ def force_recalculate_course_and_subsection_grades(sender, user, course_key, **k
...
@@ -254,7 +254,8 @@ def force_recalculate_course_and_subsection_grades(sender, user, course_key, **k
Updates a saved course grade, forcing the subsection grades
Updates a saved course grade, forcing the subsection grades
from which it is calculated to update along the way.
from which it is calculated to update along the way.
"""
"""
if
CourseGradeFactory
()
.
read
(
user
,
course_key
=
course_key
):
previous_course_grade
=
CourseGradeFactory
()
.
read
(
user
,
course_key
=
course_key
)
if
previous_course_grade
and
previous_course_grade
.
attempted
:
CourseGradeFactory
()
.
update
(
user
=
user
,
course_key
=
course_key
,
force_update_subsections
=
True
)
CourseGradeFactory
()
.
update
(
user
=
user
,
course_key
=
course_key
,
force_update_subsections
=
True
)
...
...
lms/djangoapps/grades/tests/test_grades.py
View file @
1febdbfa
...
@@ -79,7 +79,7 @@ class TestGradeIteration(SharedModuleStoreTestCase):
...
@@ -79,7 +79,7 @@ class TestGradeIteration(SharedModuleStoreTestCase):
self
.
assertIsNone
(
course_grade
.
letter_grade
)
self
.
assertIsNone
(
course_grade
.
letter_grade
)
self
.
assertEqual
(
course_grade
.
percent
,
0.0
)
self
.
assertEqual
(
course_grade
.
percent
,
0.0
)
@patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
create
'
)
@patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.
read
'
)
def
test_grading_exception
(
self
,
mock_course_grade
):
def
test_grading_exception
(
self
,
mock_course_grade
):
"""Test that we correctly capture exception messages that bubble up from
"""Test that we correctly capture exception messages that bubble up from
grading. Note that we only see errors at this level if the grading
grading. Note that we only see errors at this level if the grading
...
@@ -287,7 +287,7 @@ class TestScoreForModule(SharedModuleStoreTestCase):
...
@@ -287,7 +287,7 @@ class TestScoreForModule(SharedModuleStoreTestCase):
answer_problem
(
cls
.
course
,
cls
.
request
,
cls
.
l
,
score
=
1
,
max_value
=
3
)
answer_problem
(
cls
.
course
,
cls
.
request
,
cls
.
l
,
score
=
1
,
max_value
=
3
)
answer_problem
(
cls
.
course
,
cls
.
request
,
cls
.
n
,
score
=
3
,
max_value
=
10
)
answer_problem
(
cls
.
course
,
cls
.
request
,
cls
.
n
,
score
=
3
,
max_value
=
10
)
cls
.
course_grade
=
CourseGradeFactory
()
.
create
(
cls
.
request
.
user
,
cls
.
course
)
cls
.
course_grade
=
CourseGradeFactory
()
.
read
(
cls
.
request
.
user
,
cls
.
course
)
def
test_score_chapter
(
self
):
def
test_score_chapter
(
self
):
earned
,
possible
=
self
.
course_grade
.
score_for_module
(
self
.
a
.
location
)
earned
,
possible
=
self
.
course_grade
.
score_for_module
(
self
.
a
.
location
)
...
...
lms/djangoapps/grades/tests/test_new.py
View file @
1febdbfa
This diff is collapsed.
Click to expand it.
lms/djangoapps/grades/tests/test_tasks.py
View file @
1febdbfa
...
@@ -164,9 +164,9 @@ class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTest
...
@@ -164,9 +164,9 @@ class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTest
self
.
assertEquals
(
mock_block_structure_create
.
call_count
,
1
)
self
.
assertEquals
(
mock_block_structure_create
.
call_count
,
1
)
@ddt.data
(
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
mongo
,
1
,
31
,
True
),
(
ModuleStoreEnum
.
Type
.
mongo
,
1
,
27
,
True
),
(
ModuleStoreEnum
.
Type
.
mongo
,
1
,
27
,
False
),
(
ModuleStoreEnum
.
Type
.
mongo
,
1
,
27
,
False
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
31
,
True
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
27
,
True
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
27
,
False
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
27
,
False
),
)
)
@ddt.unpack
@ddt.unpack
...
@@ -179,8 +179,8 @@ class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTest
...
@@ -179,8 +179,8 @@ class RecalculateSubsectionGradeTest(HasCourseWithProblemsMixin, ModuleStoreTest
self
.
_apply_recalculate_subsection_grade
()
self
.
_apply_recalculate_subsection_grade
()
@ddt.data
(
@ddt.data
(
(
ModuleStoreEnum
.
Type
.
mongo
,
1
,
31
),
(
ModuleStoreEnum
.
Type
.
mongo
,
1
,
27
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
31
),
(
ModuleStoreEnum
.
Type
.
split
,
3
,
27
),
)
)
@ddt.unpack
@ddt.unpack
def
test_query_counts_dont_change_with_more_content
(
self
,
default_store
,
num_mongo_calls
,
num_sql_calls
):
def
test_query_counts_dont_change_with_more_content
(
self
,
default_store
,
num_mongo_calls
,
num_sql_calls
):
...
...
lms/djangoapps/grades/tests/utils.py
View file @
1febdbfa
...
@@ -12,17 +12,21 @@ from xmodule.graders import ProblemScore
...
@@ -12,17 +12,21 @@ from xmodule.graders import ProblemScore
@contextmanager
@contextmanager
def
mock_passing_grade
(
grade_pass
=
'Pass'
,
percent
=
0.75
,
):
def
mock_passing_grade
(
letter_grade
=
'Pass'
,
percent
=
0.75
,
):
"""
"""
Mock the grading function to always return a passing grade.
Mock the grading function to always return a passing grade.
"""
"""
with
patch
(
'lms.djangoapps.grades.course_grade.CourseGrade._compute_letter_grade'
)
as
mock_letter_grade
:
passing_grade_fields
=
dict
(
with
patch
(
'lms.djangoapps.grades.course_grade.CourseGrade._compute_percent'
)
as
mock_percent_grade
:
letter_grade
=
letter_grade
,
with
patch
(
'lms.djangoapps.grades.course_grade.CourseGrade.attempted'
)
as
mock_attempted
:
percent
=
percent
,
mock_letter_grade
.
return_value
=
grade_pass
passed
=
letter_grade
is
not
None
,
mock_percent_grade
.
return_value
=
percent
attempted
=
True
,
mock_attempted
.
return_value
=
True
)
yield
with
patch
(
'lms.djangoapps.grades.course_grade_factory.CourseGradeFactory.read'
)
as
mock_grade_read
:
mock_grade_read
.
return_value
=
MagicMock
(
**
passing_grade_fields
)
with
patch
(
'lms.djangoapps.grades.course_grade.CourseGrade.update'
)
as
mock_grade_update
:
mock_grade_update
.
return_value
=
MagicMock
(
**
passing_grade_fields
)
yield
@contextmanager
@contextmanager
...
...
lms/djangoapps/instructor/tests/test_spoc_gradebook.py
View file @
1febdbfa
...
@@ -7,6 +7,7 @@ from nose.plugins.attrib import attr
...
@@ -7,6 +7,7 @@ from nose.plugins.attrib import attr
from
capa.tests.response_xml_factory
import
StringResponseXMLFactory
from
capa.tests.response_xml_factory
import
StringResponseXMLFactory
from
courseware.tests.factories
import
StudentModuleFactory
from
courseware.tests.factories
import
StudentModuleFactory
from
lms.djangoapps.grades.tasks
import
compute_all_grades_for_course
from
student.tests.factories
import
AdminFactory
,
CourseEnrollmentFactory
,
UserFactory
from
student.tests.factories
import
AdminFactory
,
CourseEnrollmentFactory
,
UserFactory
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
from
xmodule.modulestore.tests.factories
import
CourseFactory
,
ItemFactory
...
@@ -73,6 +74,7 @@ class TestGradebook(SharedModuleStoreTestCase):
...
@@ -73,6 +74,7 @@ class TestGradebook(SharedModuleStoreTestCase):
course_id
=
self
.
course
.
id
,
course_id
=
self
.
course
.
id
,
module_state_key
=
item
.
location
module_state_key
=
item
.
location
)
)
compute_all_grades_for_course
.
apply_async
(
kwargs
=
{
'course_key'
:
unicode
(
self
.
course
.
id
)})
self
.
response
=
self
.
client
.
get
(
reverse
(
self
.
response
=
self
.
client
.
get
(
reverse
(
'spoc_gradebook'
,
'spoc_gradebook'
,
...
...
lms/djangoapps/instructor/views/gradebook_api.py
View file @
1febdbfa
...
@@ -89,7 +89,7 @@ def get_grade_book_page(request, course, course_key):
...
@@ -89,7 +89,7 @@ def get_grade_book_page(request, course, course_key):
'username'
:
student
.
username
,
'username'
:
student
.
username
,
'id'
:
student
.
id
,
'id'
:
student
.
id
,
'email'
:
student
.
email
,
'email'
:
student
.
email
,
'grade_summary'
:
CourseGradeFactory
()
.
create
(
student
,
course
)
.
summary
'grade_summary'
:
CourseGradeFactory
()
.
read
(
student
,
course
)
.
summary
}
}
for
student
in
enrolled_students
for
student
in
enrolled_students
]
]
...
...
lms/djangoapps/instructor_task/tests/test_integration.py
View file @
1febdbfa
...
@@ -131,7 +131,7 @@ class TestRescoringTask(TestIntegrationTask):
...
@@ -131,7 +131,7 @@ class TestRescoringTask(TestIntegrationTask):
# are in sync.
# are in sync.
expected_subsection_grade
=
expected_score
expected_subsection_grade
=
expected_score
course_grade
=
CourseGradeFactory
()
.
create
(
user
,
self
.
course
)
course_grade
=
CourseGradeFactory
()
.
read
(
user
,
self
.
course
)
self
.
assertEquals
(
self
.
assertEquals
(
course_grade
.
graded_subsections_by_format
[
'Homework'
][
self
.
problem_section
.
location
]
.
graded_total
.
earned
,
course_grade
.
graded_subsections_by_format
[
'Homework'
][
self
.
problem_section
.
location
]
.
graded_total
.
earned
,
expected_subsection_grade
,
expected_subsection_grade
,
...
...
lms/djangoapps/instructor_task/tests/test_tasks_helper.py
View file @
1febdbfa
...
@@ -395,7 +395,7 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase):
...
@@ -395,7 +395,7 @@ class TestInstructorGradeReport(InstructorGradeReportTestCase):
RequestCache
.
clear_request_cache
()
RequestCache
.
clear_request_cache
()
expected_query_count
=
41
expected_query_count
=
36
with
patch
(
'lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'
):
with
patch
(
'lms.djangoapps.instructor_task.tasks_helper.runner._get_current_task'
):
with
check_mongo_calls
(
mongo_count
):
with
check_mongo_calls
(
mongo_count
):
with
self
.
assertNumQueries
(
expected_query_count
):
with
self
.
assertNumQueries
(
expected_query_count
):
...
@@ -1976,7 +1976,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
...
@@ -1976,7 +1976,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
'failed'
:
3
,
'failed'
:
3
,
'skipped'
:
2
'skipped'
:
2
}
}
with
self
.
assertNumQueries
(
1
7
6
):
with
self
.
assertNumQueries
(
1
0
6
):
self
.
assertCertificatesGenerated
(
task_input
,
expected_results
)
self
.
assertCertificatesGenerated
(
task_input
,
expected_results
)
expected_results
=
{
expected_results
=
{
...
...
lms/djangoapps/lti_provider/tasks.py
View file @
1febdbfa
...
@@ -110,7 +110,7 @@ def send_composite_outcome(user_id, course_id, assignment_id, version):
...
@@ -110,7 +110,7 @@ def send_composite_outcome(user_id, course_id, assignment_id, version):
mapped_usage_key
=
assignment
.
usage_key
.
map_into_course
(
course_key
)
mapped_usage_key
=
assignment
.
usage_key
.
map_into_course
(
course_key
)
user
=
User
.
objects
.
get
(
id
=
user_id
)
user
=
User
.
objects
.
get
(
id
=
user_id
)
course
=
modulestore
()
.
get_course
(
course_key
,
depth
=
0
)
course
=
modulestore
()
.
get_course
(
course_key
,
depth
=
0
)
course_grade
=
CourseGradeFactory
()
.
create
(
user
,
course
)
course_grade
=
CourseGradeFactory
()
.
read
(
user
,
course
)
earned
,
possible
=
course_grade
.
score_for_module
(
mapped_usage_key
)
earned
,
possible
=
course_grade
.
score_for_module
(
mapped_usage_key
)
if
possible
==
0
:
if
possible
==
0
:
weighted_score
=
0
weighted_score
=
0
...
...
lms/djangoapps/lti_provider/tests/test_tasks.py
View file @
1febdbfa
...
@@ -101,7 +101,7 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
...
@@ -101,7 +101,7 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
)
)
self
.
course_grade
=
MagicMock
()
self
.
course_grade
=
MagicMock
()
self
.
course_grade_mock
=
self
.
setup_patch
(
self
.
course_grade_mock
=
self
.
setup_patch
(
'lti_provider.tasks.CourseGradeFactory.
create
'
,
self
.
course_grade
'lti_provider.tasks.CourseGradeFactory.
read
'
,
self
.
course_grade
)
)
self
.
module_store
=
MagicMock
()
self
.
module_store
=
MagicMock
()
self
.
module_store
.
get_item
=
MagicMock
(
return_value
=
self
.
descriptor
)
self
.
module_store
.
get_item
=
MagicMock
(
return_value
=
self
.
descriptor
)
...
...
lms/djangoapps/shoppingcart/tests/test_models.py
View file @
1febdbfa
...
@@ -247,12 +247,8 @@ class OrderTest(ModuleStoreTestCase):
...
@@ -247,12 +247,8 @@ class OrderTest(ModuleStoreTestCase):
self
.
assertEqual
(
cart
.
status
,
status
)
self
.
assertEqual
(
cart
.
status
,
status
)
self
.
assertEqual
(
item
.
status
,
status
)
self
.
assertEqual
(
item
.
status
,
status
)
@override_settings
(
@override_settings
(
LMS_SEGMENT_KEY
=
"foobar"
)
LMS_SEGMENT_KEY
=
"foobar"
,
@patch.dict
(
settings
.
FEATURES
,
{
'STORE_BILLING_INFO'
:
True
})
FEATURES
=
{
'STORE_BILLING_INFO'
:
True
,
}
)
def
test_purchase
(
self
):
def
test_purchase
(
self
):
# This test is for testing the subclassing functionality of OrderItem, but in
# This test is for testing the subclassing functionality of OrderItem, but in
# order to do this, we end up testing the specific functionality of
# order to do this, we end up testing the specific functionality of
...
@@ -914,12 +910,8 @@ class CertificateItemTest(ModuleStoreTestCase):
...
@@ -914,12 +910,8 @@ class CertificateItemTest(ModuleStoreTestCase):
cert_item
=
CertificateItem
.
add_to_order
(
cart
,
self
.
course_key
,
self
.
cost
,
'honor'
)
cert_item
=
CertificateItem
.
add_to_order
(
cart
,
self
.
course_key
,
self
.
cost
,
'honor'
)
self
.
assertEquals
(
cert_item
.
single_item_receipt_template
,
'shoppingcart/receipt.html'
)
self
.
assertEquals
(
cert_item
.
single_item_receipt_template
,
'shoppingcart/receipt.html'
)
@override_settings
(
@override_settings
(
LMS_SEGMENT_KEY
=
"foobar"
)
LMS_SEGMENT_KEY
=
"foobar"
,
@patch.dict
(
settings
.
FEATURES
,
{
'STORE_BILLING_INFO'
:
True
})
FEATURES
=
{
'STORE_BILLING_INFO'
:
True
,
}
)
@patch
(
'student.models.CourseEnrollment.refund_cutoff_date'
)
@patch
(
'student.models.CourseEnrollment.refund_cutoff_date'
)
def
test_refund_cert_callback_no_expiration
(
self
,
cutoff_date
):
def
test_refund_cert_callback_no_expiration
(
self
,
cutoff_date
):
# When there is no expiration date on a verified mode, the user can always get a refund
# When there is no expiration date on a verified mode, the user can always get a refund
...
@@ -956,12 +948,8 @@ class CertificateItemTest(ModuleStoreTestCase):
...
@@ -956,12 +948,8 @@ class CertificateItemTest(ModuleStoreTestCase):
self
.
assertFalse
(
target_certs
[
0
]
.
refund_requested_time
)
self
.
assertFalse
(
target_certs
[
0
]
.
refund_requested_time
)
self
.
assertEquals
(
target_certs
[
0
]
.
order
.
status
,
'purchased'
)
self
.
assertEquals
(
target_certs
[
0
]
.
order
.
status
,
'purchased'
)
@override_settings
(
@override_settings
(
LMS_SEGMENT_KEY
=
"foobar"
)
LMS_SEGMENT_KEY
=
"foobar"
,
@patch.dict
(
settings
.
FEATURES
,
{
'STORE_BILLING_INFO'
:
True
})
FEATURES
=
{
'STORE_BILLING_INFO'
:
True
,
}
)
@patch
(
'student.models.CourseEnrollment.refund_cutoff_date'
)
@patch
(
'student.models.CourseEnrollment.refund_cutoff_date'
)
def
test_refund_cert_callback_before_expiration
(
self
,
cutoff_date
):
def
test_refund_cert_callback_before_expiration
(
self
,
cutoff_date
):
# If the expiration date has not yet passed on a verified mode, the user can be refunded
# If the expiration date has not yet passed on a verified mode, the user can be refunded
...
...
lms/envs/bok_choy.py
View file @
1febdbfa
...
@@ -89,13 +89,17 @@ BLOCK_STRUCTURES_SETTINGS = dict(
...
@@ -89,13 +89,17 @@ BLOCK_STRUCTURES_SETTINGS = dict(
TASK_DEFAULT_RETRY_DELAY
=
0
,
TASK_DEFAULT_RETRY_DELAY
=
0
,
)
)
###################### Grade
Download
s ######################
###################### Grades ######################
GRADES_DOWNLOAD
=
{
GRADES_DOWNLOAD
=
{
'STORAGE_TYPE'
:
'localfs'
,
'STORAGE_TYPE'
:
'localfs'
,
'BUCKET'
:
'edx-grades'
,
'BUCKET'
:
'edx-grades'
,
'ROOT_PATH'
:
os
.
path
.
join
(
mkdtemp
(),
'edx-s3'
,
'grades'
),
'ROOT_PATH'
:
os
.
path
.
join
(
mkdtemp
(),
'edx-s3'
,
'grades'
),
}
}
FEATURES
[
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
]
=
True
FEATURES
[
'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS'
]
=
True
# Configure the LMS to use our stub XQueue implementation
# Configure the LMS to use our stub XQueue implementation
XQUEUE_INTERFACE
[
'url'
]
=
'http://localhost:8040'
XQUEUE_INTERFACE
[
'url'
]
=
'http://localhost:8040'
...
...
lms/envs/test.py
View file @
1febdbfa
...
@@ -307,6 +307,7 @@ FEATURES['ENABLE_VIDEO_ABSTRACTION_LAYER_API'] = True
...
@@ -307,6 +307,7 @@ FEATURES['ENABLE_VIDEO_ABSTRACTION_LAYER_API'] = True
########################### Grades #################################
########################### Grades #################################
FEATURES
[
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
]
=
True
FEATURES
[
'PERSISTENT_GRADES_ENABLED_FOR_ALL_TESTS'
]
=
True
FEATURES
[
'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS'
]
=
True
###################### Payment ##############################3
###################### Payment ##############################3
# Enable fake payment processing page
# Enable fake payment processing page
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment