Commit c810ef22 by Alan Boudreault

Improved LightChildField class and Fix load_student_data

parent 8b308e49
...@@ -25,9 +25,9 @@ ...@@ -25,9 +25,9 @@
import logging import logging
import json import json
import copy
from lazy import lazy from lazy import lazy
from weakref import WeakKeyDictionary
from cStringIO import StringIO from cStringIO import StringIO
from lxml import etree from lxml import etree
...@@ -140,11 +140,6 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin): ...@@ -140,11 +140,6 @@ class LightChildrenMixin(XBlockWithChildrenFragmentsMixin):
Replacement for ```self.runtime.render_child()``` Replacement for ```self.runtime.render_child()```
""" """
# load student_data
for lightchild in self.get_children_objects():
if isinstance(lightchild, LightChild):
lightchild.load_student_data()
frag = getattr(child, view_name)(context) frag = getattr(child, view_name)(context)
frag.content = u'<div class="xblock-light-child" name="{}" data-type="{}">{}</div>'.format( frag.content = u'<div class="xblock-light-child" name="{}" data-type="{}">{}</div>'.format(
child.name, child.__class__.__name__, frag.content) child.name, child.__class__.__name__, frag.content)
...@@ -215,30 +210,9 @@ class LightChild(Plugin, LightChildrenMixin): ...@@ -215,30 +210,9 @@ class LightChild(Plugin, LightChildrenMixin):
entry_point = 'xblock.light_children' entry_point = 'xblock.light_children'
def __init__(self, parent): def __init__(self, parent):
self.__dict__['_field_data'] = {} # Keep a track of the field class type, for setattr
self.parent = parent self.parent = parent
self.xblock_container = parent.xblock_container self.xblock_container = parent.xblock_container
self._student_data_loaded = False
# Instanciate our LightChild fields
# TODO HACK, Since we are not replacing the fields attribute directly, we need to
# instanciate new fields for our LightChild.
fields = [(attr, value) for attr, value in self.__class__.__dict__.iteritems() if \
isinstance(value, LightChildField)]
for attr, value in fields:
self._field_data[attr] = value.__class__
self.__dict__[attr] = value.get() # set the default value
@lazy
def student_data(self):
"""
Use lazy property instead of XBlock field, as __init__() doesn't support
overwriting field values
"""
if not self.name:
return ''
student_data = self.get_lightchild_model_object().student_data
return student_data
@property @property
def runtime(self): def runtime(self):
...@@ -256,11 +230,26 @@ class LightChild(Plugin, LightChildrenMixin): ...@@ -256,11 +230,26 @@ class LightChild(Plugin, LightChildrenMixin):
xmodule_runtime = xmodule_runtime() xmodule_runtime = xmodule_runtime()
return xmodule_runtime return xmodule_runtime
@lazy
def student_data(self):
"""
Use lazy property instead of XBlock field, as __init__() doesn't support
overwriting field values
"""
if not self.name:
return ''
student_data = self.get_lightchild_model_object().student_data
return student_data
def load_student_data(self): def load_student_data(self):
""" """
Load the values from the student_data in the database. Load the student data from the database.
""" """
if self._student_data_loaded:
return
fields = self.get_fields_to_save() fields = self.get_fields_to_save()
if not fields or not self.student_data: if not fields or not self.student_data:
return return
...@@ -270,6 +259,8 @@ class LightChild(Plugin, LightChildrenMixin): ...@@ -270,6 +259,8 @@ class LightChild(Plugin, LightChildrenMixin):
if field in student_data: if field in student_data:
setattr(self, field, student_data[field]) setattr(self, field, student_data[field])
self._student_data_loaded = True
@classmethod @classmethod
def get_fields_to_save(cls): def get_fields_to_save(cls):
""" """
...@@ -319,13 +310,6 @@ class LightChild(Plugin, LightChildrenMixin): ...@@ -319,13 +310,6 @@ class LightChild(Plugin, LightChildrenMixin):
) )
return lightchild_data return lightchild_data
def __setattr__(self, name, value):
if name in self._field_data:
self.__dict__[name] = self._field_data[name].set(value) # use the class type setter
else:
super(LightChild, self).__setattr__(name, value)
class LightChildField(object): class LightChildField(object):
""" """
...@@ -333,52 +317,38 @@ class LightChildField(object): ...@@ -333,52 +317,38 @@ class LightChildField(object):
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.value = kwargs.get('default', '') self.default = kwargs.get('default', '')
self.data = WeakKeyDictionary()
def __nonzero__(self): def __get__(self, instance, name):
return bool(self.value)
def get(self): # A LightChildField can depend on student_data
return self.value instance.load_student_data()
@classmethod return self.data.get(instance, self.default)
def set(cls, value):
return value
def __set__(self, instance, value):
self.data[instance] = value
class String(LightChildField): class String(LightChildField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.value = kwargs.get('default', '') or '' super(String, self).__init__(*args, **kwargs)
self.default = kwargs.get('default', '') or ''
def __str__(self):
return self.value
def split(self, *args, **kwargs): # def split(self, *args, **kwargs):
return self.value.split(*args, **kwargs) # return self.value.split(*args, **kwargs)
class Integer(LightChildField): class Integer(LightChildField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.value = kwargs.get('default', 0) super(Integer, self).__init__(*args, **kwargs)
self.default = kwargs.get('default', 0)
def __str__(self): def __set__(self, instance, value):
return str(self.value)
@classmethod
def set(cls, value):
try: try:
value = int(value) self.data[instance] = int(value)
except (TypeError, ValueError): # not an integer except (TypeError, ValueError): # not an integer
return 0 self.data[instance] = 0
return value
def __nonzero__(self):
try:
int(self.value)
except (TypeError, ValueError): # not an integer
return False
return self.value is not None
class Boolean(LightChildField): class Boolean(LightChildField):
...@@ -387,7 +357,8 @@ class Boolean(LightChildField): ...@@ -387,7 +357,8 @@ class Boolean(LightChildField):
class List(LightChildField): class List(LightChildField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.value = kwargs.get('default', []) super(List, self).__init__(*args, **kwargs)
self.default = kwargs.get('default', [])
class Scope(object): class Scope(object):
......
...@@ -33,7 +33,7 @@ from xblock.core import XBlock ...@@ -33,7 +33,7 @@ from xblock.core import XBlock
from xblock.fields import Boolean, Scope, String from xblock.fields import Boolean, Scope, String
from xblock.fragment import Fragment from xblock.fragment import Fragment
from .light_children import XBlockWithLightChildren, LightChild from .light_children import XBlockWithLightChildren
from .message import MentoringMessageBlock from .message import MentoringMessageBlock
from .utils import get_scenarios_from_path, load_resource, render_template from .utils import get_scenarios_from_path, load_resource, render_template
...@@ -114,8 +114,6 @@ class MentoringBlock(XBlockWithLightChildren): ...@@ -114,8 +114,6 @@ class MentoringBlock(XBlockWithLightChildren):
completed = True completed = True
for child in self.get_children_objects(): for child in self.get_children_objects():
if child.name and child.name in submissions: if child.name and child.name in submissions:
if isinstance(child, LightChild):
child.load_student_data()
submission = submissions[child.name] submission = submissions[child.name]
child_result = child.submit(submission) child_result = child.submit(submission)
submit_results.append([child.name, child_result]) submit_results.append([child.name, child_result])
......
...@@ -88,7 +88,7 @@ class MRQBlock(QuestionnaireAbstractBlock): ...@@ -88,7 +88,7 @@ class MRQBlock(QuestionnaireAbstractBlock):
if not completed: if not completed:
setattr(self, 'num_attempts', self.num_attempts + 1) setattr(self, 'num_attempts', self.num_attempts + 1)
if self.num_attempts >= self.max_attempts: if self.max_attempts > 0 and self.num_attempts >= self.max_attempts:
completed = True completed = True
self.message += u' You have reached the maximum number of attempts for this question. ' \ self.message += u' You have reached the maximum number of attempts for this question. ' \
u'Your next answers won''t be saved. You can check the answer(s) using the "Show Answer(s)" button.' u'Your next answers won''t be saved. You can check the answer(s) using the "Show Answer(s)" button.'
......
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