Commit 07ce76b3 by Utkarsh

Merge pull request #8722 from edx/utkjad/injecting_callstackmanager

Adding entries of Call Stack Manager in StudentModule and StudentModuleHistory
parents f3caef9b 10a38638
......@@ -25,6 +25,7 @@ from model_utils.models import TimeStampedModel
from student.models import user_by_anonymous_id
from submissions.models import score_set, score_reset
from openedx.core.djangoapps.call_stack_manager import CallStackManager, CallStackMixin
from xmodule_django.models import CourseKeyField, LocationKeyField, BlockTypeKeyField # pylint: disable=import-error
log = logging.getLogger(__name__)
......@@ -68,11 +69,20 @@ class ChunkingManager(models.Manager):
return res
class StudentModule(models.Model):
class ChunkingCallStackManager(CallStackManager, ChunkingManager):
"""
A derived class of ChunkingManager, and CallStackManager
"""
pass
class StudentModule(CallStackMixin, models.Model):
"""
Keeps student state for a particular module in a particular course.
"""
objects = ChunkingManager()
# uses both ChunkingManager and CallStackManager in ChuckingCallStackManager
objects = ChunkingCallStackManager()
MODEL_TAGS = ['course_id', 'module_type']
# For a homework problem, contains a JSON
......@@ -84,7 +94,7 @@ class StudentModule(models.Model):
('chapter', 'Section'),
('sequential', 'Subsection'),
('library_content', 'Library Content'))
## These three are the key for the object
# These three are the key for the object
module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='problem', db_index=True)
# Key used to share state. This is the XBlock usage_id
......@@ -142,10 +152,13 @@ class StudentModule(models.Model):
return unicode(repr(self))
class StudentModuleHistory(models.Model):
class StudentModuleHistory(CallStackMixin, models.Model):
"""Keeps a complete history of state changes for a given XModule for a given
Student. Right now, we restrict this to problems so that the table doesn't
explode in size."""
# Add call stack manager as default Manager
objects = CallStackManager()
HISTORY_SAVING_TYPES = {'problem'}
class Meta(object): # pylint: disable=missing-docstring
......
......@@ -18,6 +18,8 @@ from courseware.models import StudentModule, StudentModuleHistory
from contracts import contract, new_contract
from opaque_keys.edx.keys import UsageKey
from openedx.core.djangoapps.call_stack_manager import donottrack
new_contract('UsageKey', UsageKey)
......@@ -25,7 +27,6 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
"""
An interface that uses the Django ORM StudentModule as a backend.
"""
class ServiceUnavailable(XBlockUserStateClient.ServiceUnavailable):
"""
This error is raised if the service backing this client is currently unavailable.
......@@ -53,6 +54,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
"""
self.user = user
@donottrack(StudentModule, StudentModuleHistory)
@contract(
username="basestring",
block_key=UsageKey,
......@@ -82,7 +84,11 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
return state
@contract(username="basestring", block_key=UsageKey, state="dict(basestring: *)", scope=ScopeBase)
@donottrack(StudentModule, StudentModuleHistory)
@contract(username="basestring",
block_key=UsageKey,
state="dict(basestring: *)",
scope=ScopeBase)
def set(self, username, block_key, state, scope=Scope.user_state):
"""
Set fields for a particular XBlock.
......@@ -95,6 +101,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
"""
self.set_many(username, {block_key: state}, scope)
@donottrack(StudentModule, StudentModuleHistory)
@contract(
username="basestring",
block_key=UsageKey,
......@@ -113,6 +120,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
"""
return self.delete_many(username, [block_key], scope, fields=fields)
@donottrack(StudentModule, StudentModuleHistory)
@contract(
username="basestring",
block_key=UsageKey,
......@@ -139,6 +147,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
field: date for (_, field, date) in results
}
@donottrack(StudentModule, StudentModuleHistory)
@contract(username="basestring", block_keys="seq(UsageKey)|set(UsageKey)")
def _get_student_modules(self, username, block_keys):
"""
......@@ -166,6 +175,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
usage_key = student_module.module_state_key.map_into_course(student_module.course_id)
yield (student_module, usage_key)
@donottrack(StudentModule, StudentModuleHistory)
@contract(
username="basestring",
block_keys="seq(UsageKey)|set(UsageKey)",
......@@ -197,6 +207,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
state = json.loads(module.state)
yield (usage_key, state)
@donottrack(StudentModule, StudentModuleHistory)
@contract(username="basestring", block_keys_to_state="dict(UsageKey: dict(basestring: *))", scope=ScopeBase)
def set_many(self, username, block_keys_to_state, scope=Scope.user_state):
"""
......@@ -243,6 +254,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
# We just read this object, so we know that we can do an update
student_module.save(force_update=True)
@donottrack(StudentModule, StudentModuleHistory)
@contract(
username="basestring",
block_keys="seq(UsageKey)|set(UsageKey)",
......@@ -276,6 +288,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
# We just read this object, so we know that we can do an update
student_module.save(force_update=True)
@donottrack(StudentModule, StudentModuleHistory)
@contract(
username="basestring",
block_keys="seq(UsageKey)|set(UsageKey)",
......@@ -308,6 +321,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
for field in json.loads(student_module.state):
yield (usage_key, field, student_module.modified)
@donottrack(StudentModule, StudentModuleHistory)
@contract(username="basestring", block_key=UsageKey, scope=ScopeBase)
def get_history(self, username, block_key, scope=Scope.user_state):
"""
......
......@@ -27,7 +27,7 @@ How to use-
4. Decorator is a parameterized decorator with class name/s as argument
How to use -
1. Import following
import from openedx.core.djangoapps.call_stack_manager import donottrack
from openedx.core.djangoapps.call_stack_manager import donottrack
"""
import logging
......@@ -132,13 +132,15 @@ def donottrack(*classes_not_to_be_tracked):
global TRACK_FLAG # pylint: disable=W0603
current_flag = TRACK_FLAG
TRACK_FLAG = False
function(*args, **kwargs)
return_value = function(*args, **kwargs)
TRACK_FLAG = current_flag
return return_value
else:
global HALT_TRACKING # pylint: disable=W0603
current_halt_track = HALT_TRACKING
HALT_TRACKING = classes_not_to_be_tracked
function(*args, **kwargs)
return_value = function(*args, **kwargs)
HALT_TRACKING = current_halt_track
return return_value
return wrapper
return real_donottrack
......@@ -109,6 +109,13 @@ def donottrack_func_child():
ModelMixin.objects.all()
@donottrack()
def donottrack_check_with_return():
""" function that returns something i.e. a wrapped function returning some value
"""
return 42
@patch('openedx.core.djangoapps.call_stack_manager.core.log.info')
@patch('openedx.core.djangoapps.call_stack_manager.core.REGULAR_EXPS', [])
class TestingCallStackManager(TestCase):
......@@ -213,3 +220,11 @@ class TestingCallStackManager(TestCase):
for __ in range(1, 5):
ModelMixinCallStckMngr(id_field=1).save()
self.assertEqual(len(log_capt.call_args_list), 1)
def test_donottrack_with_return(self, log_capt):
""" Test for @donottrack
Checks if wrapper function returns the same value as wrapped function
"""
everything = donottrack_check_with_return()
self.assertEqual(everything, 42)
self.assertEqual(len(log_capt.call_args_list), 0)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment