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
Show 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__)
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
):
super
(
BlockRecordSet
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
def
__new__
(
cls
,
blocks
):
return
super
(
BlockRecordList
,
cls
)
.
__new__
(
cls
,
tuple
(
blocks
))
def
__init__
(
self
,
blocks
):
super
(
BlockRecordList
,
self
)
.
__init__
(
blocks
)
self
.
_json
=
None
self
.
_hash
=
None
...
...
@@ -56,8 +59,7 @@ class BlockRecordSet(frozenset):
stable ordering.
"""
if
self
.
_json
is
None
:
sorted_blocks
=
sorted
(
self
,
key
=
attrgetter
(
'locator'
))
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
sorted_blocks
]
list_of_block_dicts
=
[
block
.
_asdict
()
for
block
in
self
]
course_key_string
=
self
.
_get_course_key_string
()
# all blocks are from the same course
for
block_dict
in
list_of_block_dicts
:
...
...
@@ -77,7 +79,7 @@ class BlockRecordSet(frozenset):
@classmethod
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
)
course_key
=
data
[
'course_key'
]
...
...
@@ -97,6 +99,13 @@ class BlockRecordSet(frozenset):
)
return
cls
(
record_generator
)
@classmethod
def
from_list
(
cls
,
blocks
):
"""
Return a BlockRecordList from a list.
"""
return
cls
(
tuple
(
blocks
))
def
to_hash
(
self
):
"""
Return a hashed version of the list of block records.
...
...
@@ -120,24 +129,18 @@ class VisibleBlocksQuerySet(models.QuerySet):
"""
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
()})
return
model
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.
"""
if
not
isinstance
(
blocks
,
BlockRecordSet
):
blocks
=
BlockRecordSet
(
blocks
)
Argument 'blocks' should be a BlockRecordList.
"""
try
:
with
transaction
.
atomic
():
model
=
self
.
create_from_blockrecords
(
blocks
)
...
...
@@ -176,7 +179,7 @@ class VisibleBlocks(models.Model):
Returns the blocks_json data stored on this model as a list of
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
):
...
...
@@ -204,7 +207,7 @@ class PersistentSubsectionGradeQuerySet(models.QuerySet):
if
not
kwargs
.
get
(
'course_id'
,
None
):
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
(
visible_blocks_id
=
visible_blocks_hash
,
**
kwargs
...
...
@@ -358,7 +361,7 @@ class PersistentSubsectionGrade(TimeStampedModel):
Modify an existing PersistentSubsectionGrade object, saving the new
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
.
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
from
lms.djangoapps.grades.models
import
(
BlockRecord
,
BlockRecord
Se
t
,
BlockRecord
Lis
t
,
PersistentSubsectionGrade
,
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}'
def
test_empty_block_record_set
(
self
):
brs
=
BlockRecord
Set
(
)
brs
=
BlockRecord
List
(()
)
self
.
assertFalse
(
brs
)
self
.
assertEqual
(
brs
.
to_json
(),
self
.
empty_json
)
self
.
assertEqual
(
BlockRecord
Se
t
.
from_json
(
self
.
empty_json
),
BlockRecord
Lis
t
.
from_json
(
self
.
empty_json
),
brs
)
...
...
@@ -108,11 +108,17 @@ class VisibleBlocksTest(GradesModelTestCase):
"""
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
):
"""
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
()]
for
block_dict
in
list_of_block_dicts
:
block_dict
[
'locator'
]
=
unicode
(
block_dict
[
'locator'
])
# BlockUsageLocator is not json-serializable
...
...
@@ -128,30 +134,34 @@ class VisibleBlocksTest(GradesModelTestCase):
self
.
assertEqual
(
expected_json
,
vblocks
.
blocks_json
)
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
same record
in the database.
When creating new vblocks,
different ordering of blocks produces
different records
in the database.
"""
stored_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_a
,
self
.
record_b
])
repeat_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
,
self
.
record_a
])
new_vblocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
([
self
.
record_b
])
stored_vblocks
=
self
.
_create_block_record_list
([
self
.
record_a
,
self
.
record_b
])
repeat_vblocks
=
self
.
_create_block_record_list
([
self
.
record_b
,
self
.
record_a
])
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
(
stored_vblocks
.
hashed
,
repeat
_vblocks
.
hashed
)
self
.
assertEqual
s
(
stored_vblocks
.
pk
,
same_order
_vblocks
.
pk
)
self
.
assertEqual
s
(
stored_vblocks
.
hashed
,
same_order
_vblocks
.
hashed
)
self
.
assertNotEqual
(
stored_vblocks
.
pk
,
new_vblocks
.
pk
)
self
.
assertNotEqual
(
stored_vblocks
.
hashed
,
new_vblocks
.
hashed
)
def
test_blocks_property
(
self
):
"""
Ensures that, given an array of BlockRecord, creating visible_blocks
and accessing
visible_blocks.blocks yields a copy of the initial array. Also, trying to set the blocks property should raise
an exception.
Ensures that, given an array of BlockRecord, creating visible_blocks
and accessing visible_blocks.blocks yields a copy of the initial array.
Also, trying to set the blocks property should raise
an exception.
"""
expected_blocks
=
[
self
.
record_a
,
self
.
record_b
]
visible_blocks
=
VisibleBlocks
.
objects
.
create_from_blockrecords
(
expected_blocks
)
self
.
assertEqual
(
BlockRecordSet
(
expected_blocks
)
,
visible_blocks
.
blocks
)
expected_blocks
=
(
self
.
record_a
,
self
.
record_b
)
visible_blocks
=
self
.
_create_block_record_list
(
expected_blocks
)
self
.
assertEqual
(
expected_blocks
,
visible_blocks
.
blocks
)
with
self
.
assertRaises
(
AttributeError
):
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