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
47e556c7
Commit
47e556c7
authored
Sep 15, 2016
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use explicit 'graded' value so grades are immune to subsection's value
TNL-5560
parent
e6b5cc9e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
96 additions
and
10 deletions
+96
-10
lms/djangoapps/grades/new/subsection_grade.py
+18
-1
lms/djangoapps/grades/tests/test_transformer.py
+28
-1
lms/djangoapps/grades/transformer.py
+50
-8
No files found.
lms/djangoapps/grades/new/subsection_grade.py
View file @
47e556c7
...
...
@@ -11,6 +11,7 @@ from courseware.model_data import ScoresClient
from
lms.djangoapps.grades.scores
import
get_score
,
possibly_scored
from
lms.djangoapps.grades.models
import
BlockRecord
,
PersistentSubsectionGrade
from
lms.djangoapps.grades.config.models
import
PersistentGradesEnabledFlag
from
lms.djangoapps.grades.transformer
import
GradesTransformer
from
student.models
import
anonymous_id_for_user
,
User
from
submissions
import
api
as
submissions_api
from
traceback
import
format_exc
...
...
@@ -173,7 +174,7 @@ class SubsectionGrade(object):
#
# Cannot grade a problem with a denominator of 0.
# TODO: None > 0 is not python 3 compatible.
block_graded
=
block
.
graded
if
possible
>
0
else
False
block_graded
=
self
.
_get_explicit_graded
(
block
,
course_structure
)
if
possible
>
0
else
False
self
.
locations_to_weighted_scores
[
block
.
location
]
=
(
Score
(
...
...
@@ -186,6 +187,22 @@ class SubsectionGrade(object):
weight
,
)
def
_get_explicit_graded
(
self
,
block
,
course_structure
):
"""
Returns the explicit graded field value for the given block
"""
field_value
=
course_structure
.
get_transformer_block_field
(
block
.
location
,
GradesTransformer
,
GradesTransformer
.
EXPLICIT_GRADED_FIELD_NAME
)
# Set to True if grading is not explicitly disabled for
# this block. This allows us to include the block's score
# in the aggregated self.graded_total, regardless of the
# inherited graded value from the subsection. (TNL-5560)
return
True
if
field_value
is
None
else
field_value
def
_persisted_model_params
(
self
,
student
):
"""
Returns the parameters for creating/updating the
...
...
lms/djangoapps/grades/tests/test_transformer.py
View file @
47e556c7
...
...
@@ -6,6 +6,8 @@ import datetime
import
pytz
import
random
import
ddt
from
student.tests.factories
import
UserFactory
from
xmodule.modulestore
import
ModuleStoreEnum
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
...
...
@@ -17,6 +19,7 @@ from openedx.core.djangoapps.content.block_structure.api import get_cache
from
..transformer
import
GradesTransformer
@ddt.ddt
class
GradesTransformerTestCase
(
CourseStructureTestCase
):
"""
Verify behavior of the GradesTransformer
...
...
@@ -194,7 +197,7 @@ class GradesTransformerTestCase(CourseStructureTestCase):
)
self
.
assertEqual
(
actual_subsections
,
{
blocks
[
sub
]
.
location
for
sub
in
expected_subsections
})
def
test_un
grad
ed_block_collection
(
self
):
def
test_un
scor
ed_block_collection
(
self
):
blocks
=
self
.
build_course_with_problems
()
block_structure
=
get_course_blocks
(
self
.
student
,
blocks
[
u'course'
]
.
location
,
self
.
transformers
)
self
.
assert_collected_xblock_fields
(
...
...
@@ -211,6 +214,7 @@ class GradesTransformerTestCase(CourseStructureTestCase):
blocks
[
u'course'
]
.
location
,
self
.
TRANSFORMER_CLASS_TO_TEST
,
max_score
=
None
,
explicit_graded
=
None
,
)
def
test_grades_collected_basic
(
self
):
...
...
@@ -227,6 +231,29 @@ class GradesTransformerTestCase(CourseStructureTestCase):
due
=
self
.
problem_metadata
[
u'due'
],
format
=
None
,
)
self
.
assert_collected_transformer_block_fields
(
block_structure
,
blocks
[
u'problem'
]
.
location
,
self
.
TRANSFORMER_CLASS_TO_TEST
,
max_score
=
0
,
explicit_graded
=
True
,
)
@ddt.data
(
True
,
False
,
None
)
def
test_graded_at_problem
(
self
,
graded
):
problem_metadata
=
{
u'has_score'
:
True
,
}
if
graded
is
not
None
:
problem_metadata
[
u'graded'
]
=
graded
blocks
=
self
.
build_course_with_problems
(
metadata
=
problem_metadata
)
block_structure
=
get_course_blocks
(
self
.
student
,
blocks
[
u'course'
]
.
location
,
self
.
transformers
)
self
.
assert_collected_transformer_block_fields
(
block_structure
,
blocks
[
u'problem'
]
.
location
,
self
.
TRANSFORMER_CLASS_TO_TEST
,
explicit_graded
=
graded
,
)
def
test_collecting_staff_only_problem
(
self
):
# Demonstrate that the problem data can by collected by the SystemUser
...
...
lms/djangoapps/grades/transformer.py
View file @
47e556c7
...
...
@@ -2,10 +2,11 @@
Grades Transformer
"""
from
django.test.client
import
RequestFactory
from
functools
import
reduce
as
functools_reduce
from
courseware.model_data
import
FieldDataCache
from
courseware.module_render
import
get_module_for_descriptor
from
lms.djangoapps.course_blocks.transformers.utils
import
collect_unioned_set_field
from
lms.djangoapps.course_blocks.transformers.utils
import
collect_unioned_set_field
,
get_field_on_block
from
openedx.core.lib.block_structure.transformer
import
BlockStructureTransformer
from
openedx.core.djangoapps.util.user_utils
import
SystemUser
...
...
@@ -17,8 +18,8 @@ class GradesTransformer(BlockStructureTransformer):
No runtime transformations are performed.
The following values are stored as xblock_fields on their respective blocks
in the
block structure:
The following values are stored as xblock_fields on their respective blocks
in the
block structure:
due: (datetime) when the problem is due.
format: (string) what type of problem it is
...
...
@@ -26,14 +27,16 @@ class GradesTransformer(BlockStructureTransformer):
has_score: (boolean)
weight: (numeric)
Additionally, the following value is calculated and stored as a
transformer_block_field
for each block:
Additionally, the following value is calculated and stored as a
transformer_block_field
for each block:
max_score: (numeric)
"""
VERSION
=
3
VERSION
=
4
FIELDS_TO_COLLECT
=
[
u'due'
,
u'format'
,
u'graded'
,
u'has_score'
,
u'weight'
,
u'course_version'
,
u'subtree_edited_on'
]
EXPLICIT_GRADED_FIELD_NAME
=
'explicit_graded'
@classmethod
def
name
(
cls
):
"""
...
...
@@ -56,6 +59,7 @@ class GradesTransformer(BlockStructureTransformer):
merged_field_name
=
'subsections'
,
filter_by
=
lambda
block_key
:
block_key
.
block_type
==
'sequential'
,
)
cls
.
_collect_explicit_graded
(
block_structure
)
def
transform
(
self
,
block_structure
,
usage_context
):
"""
...
...
@@ -64,6 +68,44 @@ class GradesTransformer(BlockStructureTransformer):
pass
@classmethod
def
_collect_explicit_graded
(
cls
,
block_structure
):
"""
Collect the 'explicit_graded' field for every block.
"""
def
_set_field
(
block_key
,
field_value
):
"""
Sets the explicit graded field to the given value for the
given block.
"""
block_structure
.
set_transformer_block_field
(
block_key
,
cls
,
cls
.
EXPLICIT_GRADED_FIELD_NAME
,
field_value
)
def
_get_field
(
block_key
):
"""
Gets the explicit graded field to the given value for the
given block.
"""
return
block_structure
.
get_transformer_block_field
(
block_key
,
cls
,
cls
.
EXPLICIT_GRADED_FIELD_NAME
)
block_types_to_ignore
=
{
'course'
,
'chapter'
,
'sequential'
}
for
block_key
in
block_structure
.
topological_traversal
():
if
block_key
.
block_type
in
block_types_to_ignore
:
_set_field
(
block_key
,
None
)
else
:
explicit_field_on_block
=
get_field_on_block
(
block_structure
.
get_xblock
(
block_key
),
'graded'
)
if
explicit_field_on_block
is
not
None
:
_set_field
(
block_key
,
explicit_field_on_block
)
else
:
values_from_parents
=
[
_get_field
(
parent
)
for
parent
in
block_structure
.
get_parents
(
block_key
)
if
parent
.
block_type
not
in
block_types_to_ignore
]
non_null_values_from_parents
=
[
value
for
value
in
values_from_parents
if
not
None
]
explicit_from_parents
=
functools_reduce
(
lambda
x
,
y
:
x
or
y
,
non_null_values_from_parents
,
None
)
_set_field
(
block_key
,
explicit_from_parents
)
@classmethod
def
_collect_max_scores
(
cls
,
block_structure
):
"""
Collect the `max_score` for every block in the provided `block_structure`.
...
...
@@ -83,8 +125,8 @@ class GradesTransformer(BlockStructureTransformer):
@staticmethod
def
_iter_scorable_xmodules
(
block_structure
):
"""
Loop through all the blocks locators in the block structure, and
retrieve
the module (XModule or XBlock) associated with that locator.
Loop through all the blocks locators in the block structure, and
retrieve
the module (XModule or XBlock) associated with that locator.
For implementation reasons, we need to pull the max_score from the
XModule, even though the data is not user specific. Here we bind the
...
...
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