Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
edx-platform-release
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Package Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Hsin-Yu Chien
edx-platform-release
Commits
d244715e
Commit
d244715e
authored
8 years ago
by
Nimisha Asthagiri
Browse files
Options
Downloads
Patches
Plain Diff
Don't sort blocks to retain order.
parent
660bc8f4
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
lms/djangoapps/grades/models.py
+23
-20
23 additions, 20 deletions
lms/djangoapps/grades/models.py
lms/djangoapps/grades/tests/test_models.py
+30
-20
30 additions, 20 deletions
lms/djangoapps/grades/tests/test_models.py
with
53 additions
and
40 deletions
lms/djangoapps/grades/models.py
+
23
−
20
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
Se
t from a
json list
.
Return a BlockRecord
Lis
t 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
(
b
lock
s
=
visible_blocks
)
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
B
lock
RecordList
.
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
(
b
lock
s
=
visible_blocks
)
visible_blocks_hash
=
VisibleBlocks
.
objects
.
hash_from_blockrecords
(
B
lock
RecordList
.
from_list
(
visible_blocks
)
)
self
.
course_version
=
course_version
or
""
self
.
subtree_edited_timestamp
=
subtree_edited_timestamp
...
...
This diff is collapsed.
Click to expand it.
lms/djangoapps/grades/tests/test_models.py
+
30
−
20
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_
blockrecord
s
([
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_matter
s
(
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
record
s
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_
blockrecord
s
(
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
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment