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
d244715e
Commit
d244715e
authored
Sep 10, 2016
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Don't sort blocks to retain order.
parent
660bc8f4
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
53 additions
and
40 deletions
+53
-40
lms/djangoapps/grades/models.py
+23
-20
lms/djangoapps/grades/tests/test_models.py
+30
-20
No files found.
lms/djangoapps/grades/models.py
View file @
d244715e
...
@@ -29,13 +29,16 @@ log = logging.getLogger(__name__)
...
@@ -29,13 +29,16 @@ log = logging.getLogger(__name__)
BlockRecord
=
namedtuple
(
'BlockRecord'
,
[
'locator'
,
'weight'
,
'max_score'
])
BlockRecord
=
namedtuple
(
'BlockRecord'
,
[
'locator'
,
'weight'
,
'max_score'
])
class
BlockRecord
Set
(
frozenset
):
class
BlockRecord
List
(
tuple
):
"""
"""
An immutable ordered
collection
of BlockRecord objects.
An immutable ordered
list
of BlockRecord objects.
"""
"""
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__new__
(
cls
,
blocks
):
super
(
BlockRecordSet
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
return
super
(
BlockRecordList
,
cls
)
.
__new__
(
cls
,
tuple
(
blocks
))
def
__init__
(
self
,
blocks
):
super
(
BlockRecordList
,
self
)
.
__init__
(
blocks
)
self
.
_json
=
None
self
.
_json
=
None
self
.
_hash
=
None
self
.
_hash
=
None
...
@@ -56,8 +59,7 @@ class BlockRecordSet(frozenset):
...
@@ -56,8 +59,7 @@ class BlockRecordSet(frozenset):
stable ordering.
stable ordering.
"""
"""
if
self
.
_json
is
None
:
if
self
.
_json
is
None
:
sorted_blocks
=
sorted
(
self
,
key
=
attrgetter
(
'locator'
))
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
self
]
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
sorted_blocks
]
course_key_string
=
self
.
_get_course_key_string
()
# all blocks are from the same course
course_key_string
=
self
.
_get_course_key_string
()
# all blocks are from the same course
for
block_dict
in
list_of_block_dicts
:
for
block_dict
in
list_of_block_dicts
:
...
@@ -77,7 +79,7 @@ class BlockRecordSet(frozenset):
...
@@ -77,7 +79,7 @@ class BlockRecordSet(frozenset):
@classmethod
@classmethod
def
from_json
(
cls
,
blockrecord_json
):
def
from_json
(
cls
,
blockrecord_json
):
"""
"""
Return a BlockRecord
Set from a json list
.
Return a BlockRecord
List from a previously serialized json
.
"""
"""
data
=
json
.
loads
(
blockrecord_json
)
data
=
json
.
loads
(
blockrecord_json
)
course_key
=
data
[
'course_key'
]
course_key
=
data
[
'course_key'
]
...
@@ -97,6 +99,13 @@ class BlockRecordSet(frozenset):
...
@@ -97,6 +99,13 @@ class BlockRecordSet(frozenset):
)
)
return
cls
(
record_generator
)
return
cls
(
record_generator
)
@classmethod
def
from_list
(
cls
,
blocks
):
"""
Return a BlockRecordList from a list.
"""
return
cls
(
tuple
(
blocks
))
def
to_hash
(
self
):
def
to_hash
(
self
):
"""
"""
Return a hashed version of the list of block records.
Return a hashed version of the list of block records.
...
@@ -120,24 +129,18 @@ class VisibleBlocksQuerySet(models.QuerySet):
...
@@ -120,24 +129,18 @@ class VisibleBlocksQuerySet(models.QuerySet):
"""
"""
Creates a new VisibleBlocks model object.
Creates a new VisibleBlocks model object.
Argument 'blocks' should be a BlockRecord
Se
t.
Argument 'blocks' should be a BlockRecord
Lis
t.
"""
"""
if
not
isinstance
(
blocks
,
BlockRecordSet
):
blocks
=
BlockRecordSet
(
blocks
)
model
,
_
=
self
.
get_or_create
(
hashed
=
blocks
.
to_hash
(),
defaults
=
{
'blocks_json'
:
blocks
.
to_json
()})
model
,
_
=
self
.
get_or_create
(
hashed
=
blocks
.
to_hash
(),
defaults
=
{
'blocks_json'
:
blocks
.
to_json
()})
return
model
return
model
def
hash_from_blockrecords
(
self
,
blocks
):
def
hash_from_blockrecords
(
self
,
blocks
):
"""
"""
Return the hash for a given
BlockRecordSet, serializ
ing the records if
Return the hash for a given
list of blocks, sav
ing the records if
possible, but returning the hash even if an IntegrityError occurs.
possible, but returning the hash even if an IntegrityError occurs.
"""
if
not
isinstance
(
blocks
,
BlockRecordSet
):
blocks
=
BlockRecordSet
(
blocks
)
Argument 'blocks' should be a BlockRecordList.
"""
try
:
try
:
with
transaction
.
atomic
():
with
transaction
.
atomic
():
model
=
self
.
create_from_blockrecords
(
blocks
)
model
=
self
.
create_from_blockrecords
(
blocks
)
...
@@ -176,7 +179,7 @@ class VisibleBlocks(models.Model):
...
@@ -176,7 +179,7 @@ class VisibleBlocks(models.Model):
Returns the blocks_json data stored on this model as a list of
Returns the blocks_json data stored on this model as a list of
BlockRecords in the order they were provided.
BlockRecords in the order they were provided.
"""
"""
return
BlockRecord
Se
t
.
from_json
(
self
.
blocks_json
)
return
BlockRecord
Lis
t
.
from_json
(
self
.
blocks_json
)
class
PersistentSubsectionGradeQuerySet
(
models
.
QuerySet
):
class
PersistentSubsectionGradeQuerySet
(
models
.
QuerySet
):
...
@@ -204,7 +207,7 @@ class PersistentSubsectionGradeQuerySet(models.QuerySet):
...
@@ -204,7 +207,7 @@ class PersistentSubsectionGradeQuerySet(models.QuerySet):
if
not
kwargs
.
get
(
'course_id'
,
None
):
if
not
kwargs
.
get
(
'course_id'
,
None
):
kwargs
[
'course_id'
]
=
kwargs
[
'usage_key'
]
.
course_key
kwargs
[
'course_id'
]
=
kwargs
[
'usage_key'
]
.
course_key
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
blocks
=
visible_blocks
)
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
BlockRecordList
.
from_list
(
visible_blocks
)
)
return
super
(
PersistentSubsectionGradeQuerySet
,
self
)
.
create
(
return
super
(
PersistentSubsectionGradeQuerySet
,
self
)
.
create
(
visible_blocks_id
=
visible_blocks_hash
,
visible_blocks_id
=
visible_blocks_hash
,
**
kwargs
**
kwargs
...
@@ -358,7 +361,7 @@ class PersistentSubsectionGrade(TimeStampedModel):
...
@@ -358,7 +361,7 @@ class PersistentSubsectionGrade(TimeStampedModel):
Modify an existing PersistentSubsectionGrade object, saving the new
Modify an existing PersistentSubsectionGrade object, saving the new
version.
version.
"""
"""
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
blocks
=
visible_blocks
)
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
BlockRecordList
.
from_list
(
visible_blocks
)
)
self
.
course_version
=
course_version
or
""
self
.
course_version
=
course_version
or
""
self
.
subtree_edited_timestamp
=
subtree_edited_timestamp
self
.
subtree_edited_timestamp
=
subtree_edited_timestamp
...
...
lms/djangoapps/grades/tests/test_models.py
View file @
d244715e
...
@@ -14,27 +14,27 @@ from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator
...
@@ -14,27 +14,27 @@ from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator
from
lms.djangoapps.grades.models
import
(
from
lms.djangoapps.grades.models
import
(
BlockRecord
,
BlockRecord
,
BlockRecord
Se
t
,
BlockRecord
Lis
t
,
PersistentSubsectionGrade
,
PersistentSubsectionGrade
,
VisibleBlocks
VisibleBlocks
)
)
class
BlockRecord
Se
tTestCase
(
TestCase
):
class
BlockRecord
Lis
tTestCase
(
TestCase
):
"""
"""
Verify the behavior of BlockRecord
Sets
, particularly around edge cases
Verify the behavior of BlockRecord
List
, particularly around edge cases
"""
"""
empty_json
=
'{"blocks":[],"course_key":null}'
empty_json
=
'{"blocks":[],"course_key":null}'
def
test_empty_block_record_set
(
self
):
def
test_empty_block_record_set
(
self
):
brs
=
BlockRecord
Set
(
)
brs
=
BlockRecord
List
(()
)
self
.
assertFalse
(
brs
)
self
.
assertFalse
(
brs
)
self
.
assertEqual
(
self
.
assertEqual
(
brs
.
to_json
(),
brs
.
to_json
(),
self
.
empty_json
self
.
empty_json
)
)
self
.
assertEqual
(
self
.
assertEqual
(
BlockRecord
Se
t
.
from_json
(
self
.
empty_json
),
BlockRecord
Lis
t
.
from_json
(
self
.
empty_json
),
brs
brs
)
)
...
@@ -108,11 +108,17 @@ class VisibleBlocksTest(GradesModelTestCase):
...
@@ -108,11 +108,17 @@ class VisibleBlocksTest(GradesModelTestCase):
"""
"""
Test the VisibleBlocks model.
Test the VisibleBlocks model.
"""
"""
def
_create_block_record_list
(
self
,
blocks
):
"""
Creates and returns a BlockRecordList for the given blocks.
"""
return
VisibleBlocks
.
objects
.
create_from_blockrecords
(
BlockRecordList
.
from_list
(
blocks
))
def
test_creation
(
self
):
def
test_creation
(
self
):
"""
"""
Happy path test to ensure basic create functionality works as expected.
Happy path test to ensure basic create functionality works as expected.
"""
"""
vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_a
])
vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
])
list_of_block_dicts
=
[
self
.
record_a
.
_asdict
()]
list_of_block_dicts
=
[
self
.
record_a
.
_asdict
()]
for
block_dict
in
list_of_block_dicts
:
for
block_dict
in
list_of_block_dicts
:
block_dict
[
'locator'
]
=
unicode
(
block_dict
[
'locator'
])
# BlockUsageLocator is not json-serializable
block_dict
[
'locator'
]
=
unicode
(
block_dict
[
'locator'
])
# BlockUsageLocator is not json-serializable
...
@@ -128,30 +134,34 @@ class VisibleBlocksTest(GradesModelTestCase):
...
@@ -128,30 +134,34 @@ class VisibleBlocksTest(GradesModelTestCase):
self
.
assertEqual
(
expected_json
,
vblocks
.
blocks_json
)
self
.
assertEqual
(
expected_json
,
vblocks
.
blocks_json
)
self
.
assertEqual
(
expected_hash
,
vblocks
.
hashed
)
self
.
assertEqual
(
expected_hash
,
vblocks
.
hashed
)
def
test_ordering_
does_not_matter
(
self
):
def
test_ordering_
matters
(
self
):
"""
"""
When creating new vblocks,
a different ordering of blocks produces the
When creating new vblocks,
different ordering of blocks produces
same record
in the database.
different records
in the database.
"""
"""
stored_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_a
,
self
.
record_b
])
stored_vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
,
self
.
record_b
])
repeat_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
,
self
.
record_a
])
repeat_vblocks
=
self
.
_create_block_record_list
([
self
.
record_b
,
self
.
record_a
])
new_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
])
same_order_vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
,
self
.
record_b
])
new_vblocks
=
self
.
_create_block_record_list
([
self
.
record_b
])
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
repeat_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
repeat_vblocks
.
hashed
)
self
.
assertEqual
(
stored_vblocks
.
pk
,
repeat
_vblocks
.
pk
)
self
.
assertEqual
s
(
stored_vblocks
.
pk
,
same_order
_vblocks
.
pk
)
self
.
assertEqual
(
stored_vblocks
.
hashed
,
repeat
_vblocks
.
hashed
)
self
.
assertEqual
s
(
stored_vblocks
.
hashed
,
same_order
_vblocks
.
hashed
)
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
new_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
new_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
new_vblocks
.
hashed
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
new_vblocks
.
hashed
)
def
test_blocks_property
(
self
):
def
test_blocks_property
(
self
):
"""
"""
Ensures that, given an array of BlockRecord, creating visible_blocks
and accessing
Ensures that, given an array of BlockRecord, creating visible_blocks
visible_blocks.blocks yields a copy of the initial array. Also, trying to set the blocks property should raise
and accessing visible_blocks.blocks yields a copy of the initial array.
an exception.
Also, trying to set the blocks property should raise
an exception.
"""
"""
expected_blocks
=
[
self
.
record_a
,
self
.
record_b
]
expected_blocks
=
(
self
.
record_a
,
self
.
record_b
)
visible_blocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
(
expected_blocks
)
visible_blocks
=
self
.
_create_block_record_list
(
expected_blocks
)
self
.
assertEqual
(
BlockRecordSet
(
expected_blocks
)
,
visible_blocks
.
blocks
)
self
.
assertEqual
(
expected_blocks
,
visible_blocks
.
blocks
)
with
self
.
assertRaises
(
AttributeError
):
with
self
.
assertRaises
(
AttributeError
):
visible_blocks
.
blocks
=
expected_blocks
visible_blocks
.
blocks
=
expected_blocks
...
...
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