From cc2d06975e24f473304f3bda0ec18a4615c1da85 Mon Sep 17 00:00:00 2001 From: cahrens Date: Wed, 24 Apr 2013 14:40:55 -0400 Subject: [PATCH] Remove duplicated StringyX definitions. --- cms/xmodule_namespace.py | 18 +----- common/lib/xmodule/xmodule/capa_module.py | 27 +-------- .../xmodule/combined_open_ended_module.py | 3 +- common/lib/xmodule/xmodule/fields.py | 41 ++++++++++++++ common/lib/xmodule/xmodule/mako_module.py | 28 ++-------- .../xmodule/xmodule/peer_grading_module.py | 3 +- .../lib/xmodule/xmodule/tests/test_fields.py | 56 ++++++++++++++++++- common/lib/xmodule/xmodule/video_module.py | 3 +- lms/xmodule_namespace.py | 29 +--------- 9 files changed, 110 insertions(+), 98 deletions(-) diff --git a/cms/xmodule_namespace.py b/cms/xmodule_namespace.py index c9bb8f4c6e..1b509a14f4 100644 --- a/cms/xmodule_namespace.py +++ b/cms/xmodule_namespace.py @@ -4,22 +4,8 @@ Namespace defining common fields used by Studio for all blocks import datetime -from xblock.core import Namespace, Boolean, Scope, ModelType, String - - -class StringyBoolean(Boolean): - """ - Reads strings from JSON as booleans. - - If the string is 'true' (case insensitive), then return True, - otherwise False. - - JSON values that aren't strings are returned as is - """ - def from_json(self, value): - if isinstance(value, basestring): - return value.lower() == 'true' - return value +from xblock.core import Namespace, Scope, ModelType, String +from xmodule.fields import StringyBoolean class DateTuple(ModelType): diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index 680305269d..dc9be6ce5f 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -16,36 +16,13 @@ from .progress import Progress from xmodule.x_module import XModule from xmodule.raw_module import RawDescriptor from xmodule.exceptions import NotFoundError, ProcessingError -from xblock.core import Integer, Scope, String, Boolean, Object, Float -from .fields import Timedelta, Date +from xblock.core import Scope, String, Boolean, Object +from .fields import Timedelta, Date, StringyInteger, StringyFloat from xmodule.util.date_utils import time_to_datetime log = logging.getLogger("mitx.courseware") -class StringyInteger(Integer): - """ - A model type that converts from strings to integers when reading from json - """ - def from_json(self, value): - try: - return int(value) - except: - return None - - -# TODO: move to fields.py and remove duplicated code. -class StringyFloat(Float): - """ - A model type that converts from string to floats when reading from json - """ - def from_json(self, value): - try: - return float(value) - except: - return None - - # Generated this many different variants of problems with rerandomize=per_student NUM_RANDOMIZATION_BINS = 20 diff --git a/common/lib/xmodule/xmodule/combined_open_ended_module.py b/common/lib/xmodule/xmodule/combined_open_ended_module.py index 120e4f743a..239adcaa41 100644 --- a/common/lib/xmodule/xmodule/combined_open_ended_module.py +++ b/common/lib/xmodule/xmodule/combined_open_ended_module.py @@ -8,8 +8,7 @@ from .x_module import XModule from xblock.core import Integer, Scope, String, Boolean, List from xmodule.open_ended_grading_classes.combined_open_ended_modulev1 import CombinedOpenEndedV1Module, CombinedOpenEndedV1Descriptor from collections import namedtuple -from .fields import Date -from xmodule.open_ended_grading_classes.xblock_field_types import StringyFloat +from .fields import Date, StringyFloat log = logging.getLogger("mitx.courseware") diff --git a/common/lib/xmodule/xmodule/fields.py b/common/lib/xmodule/xmodule/fields.py index bb85714252..3d56b7941e 100644 --- a/common/lib/xmodule/xmodule/fields.py +++ b/common/lib/xmodule/xmodule/fields.py @@ -7,6 +7,8 @@ from xblock.core import ModelType import datetime import dateutil.parser +from xblock.core import Integer, Float, Boolean + log = logging.getLogger(__name__) @@ -81,3 +83,42 @@ class Timedelta(ModelType): if cur_value > 0: values.append("%d %s" % (cur_value, attr)) return ' '.join(values) + + +class StringyInteger(Integer): + """ + A model type that converts from strings to integers when reading from json. + If value does not parse as an int, returns None. + """ + def from_json(self, value): + try: + return int(value) + except: + return None + + +class StringyFloat(Float): + """ + A model type that converts from string to floats when reading from json. + If value does not parse as a float, returns None. + """ + def from_json(self, value): + try: + return float(value) + except: + return None + + +class StringyBoolean(Boolean): + """ + Reads strings from JSON as booleans. + + If the string is 'true' (case insensitive), then return True, + otherwise False. + + JSON values that aren't strings are returned as-is. + """ + def from_json(self, value): + if isinstance(value, basestring): + return value.lower() == 'true' + return value diff --git a/common/lib/xmodule/xmodule/mako_module.py b/common/lib/xmodule/xmodule/mako_module.py index 75dd655d41..84db6ad779 100644 --- a/common/lib/xmodule/xmodule/mako_module.py +++ b/common/lib/xmodule/xmodule/mako_module.py @@ -1,7 +1,5 @@ from .x_module import XModuleDescriptor, DescriptorSystem from .modulestore.inheritance import own_metadata -from xblock.core import Scope - class MakoDescriptorSystem(DescriptorSystem): @@ -46,26 +44,10 @@ class MakoModuleDescriptor(XModuleDescriptor): # cdodge: encapsulate a means to expose "editable" metadata fields (i.e. not internal system metadata) @property def editable_metadata_fields(self): -# fields = {} -# for field, value in own_metadata(self).items(): -# if field in self.system_metadata_fields: -# continue -# -# fields[field] = value -# return fields - inherited_metadata = getattr(self, '_inherited_metadata', {}) - metadata = {} - for field in self.fields: - # Only save metadata that wasn't inherited - if field.scope != Scope.settings or field.name in self.system_metadata_fields: + fields = {} + for field, value in own_metadata(self).items(): + if field in self.system_metadata_fields: continue - if field.name in self._model_data: - metadata[field.name] = self._model_data[field.name] - if field.name in inherited_metadata and self._model_data.get(field.name) == inherited_metadata.get( - field.name): - metadata[field.name] = str(metadata[field.name]) + ' INHERITED' - else: - metadata[field.name] = str(getattr(self, field.name)) + ' DEFAULT' - - return metadata + fields[field] = value + return fields diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py index db4514d0e0..35f2fa2d76 100644 --- a/common/lib/xmodule/xmodule/peer_grading_module.py +++ b/common/lib/xmodule/xmodule/peer_grading_module.py @@ -11,8 +11,7 @@ from xmodule.raw_module import RawDescriptor from xmodule.modulestore.django import modulestore from .timeinfo import TimeInfo from xblock.core import Object, Integer, Boolean, String, Scope -from xmodule.open_ended_grading_classes.xblock_field_types import StringyFloat -from xmodule.fields import Date +from xmodule.fields import Date, StringyFloat from xmodule.open_ended_grading_classes.peer_grading_service import PeerGradingService, GradingServiceError, MockPeerGradingService from open_ended_grading_classes import combined_open_ended_rubric diff --git a/common/lib/xmodule/xmodule/tests/test_fields.py b/common/lib/xmodule/xmodule/tests/test_fields.py index 7c8872efc1..9642f7c595 100644 --- a/common/lib/xmodule/xmodule/tests/test_fields.py +++ b/common/lib/xmodule/xmodule/tests/test_fields.py @@ -1,8 +1,8 @@ -"""Tests for Date class defined in fields.py.""" +"""Tests for classes defined in fields.py.""" import datetime import unittest from django.utils.timezone import UTC -from xmodule.fields import Date +from xmodule.fields import Date, StringyFloat, StringyInteger, StringyBoolean import time class DateTest(unittest.TestCase): @@ -78,3 +78,55 @@ class DateTest(unittest.TestCase): DateTest.date.from_json("2012-12-31T23:00:01-01:00")), "2013-01-01T00:00:01Z") + +class StringyIntegerTest(unittest.TestCase): + def assertEquals(self, expected, arg): + self.assertEqual(expected, StringyInteger().from_json(arg)) + + def test_integer(self): + self.assertEquals(5, '5') + self.assertEquals(0, '0') + self.assertEquals(-1023, '-1023') + + def test_none(self): + self.assertEquals(None, None) + self.assertEquals(None, 'abc') + self.assertEquals(None, '[1]') + self.assertEquals(None, '1.023') + + +class StringyFloatTest(unittest.TestCase): + + def assertEquals(self, expected, arg): + self.assertEqual(expected, StringyFloat().from_json(arg)) + + def test_float(self): + self.assertEquals(.23, '.23') + self.assertEquals(5, '5') + self.assertEquals(0, '0.0') + self.assertEquals(-1023.22, '-1023.22') + + def test_none(self): + self.assertEquals(None, None) + self.assertEquals(None, 'abc') + self.assertEquals(None, '[1]') + + +class StringyBooleanTest(unittest.TestCase): + + def assertEquals(self, expected, arg): + self.assertEqual(expected, StringyBoolean().from_json(arg)) + + def test_false(self): + self.assertEquals(False, "false") + self.assertEquals(False, "False") + self.assertEquals(False, "") + self.assertEquals(False, "hahahahah") + + def test_true(self): + self.assertEquals(True, "true") + self.assertEquals(True, "TruE") + + def test_pass_through(self): + self.assertEquals(123, 123) + diff --git a/common/lib/xmodule/xmodule/video_module.py b/common/lib/xmodule/xmodule/video_module.py index 2343d24a57..fabc75037c 100644 --- a/common/lib/xmodule/xmodule/video_module.py +++ b/common/lib/xmodule/xmodule/video_module.py @@ -20,7 +20,8 @@ log = logging.getLogger(__name__) class VideoFields(object): data = String(help="XML data for the problem", scope=Scope.content) position = Integer(help="Current position in the video", scope=Scope.user_state, default=0) - display_name = String(help="Display name for this module", scope=Scope.settings) + # display_name is used by the LMS on the sequential ribbon (displayed as a tooltip) + display_name = XModule.display_name class VideoModule(VideoFields, XModule): diff --git a/lms/xmodule_namespace.py b/lms/xmodule_namespace.py index 14a6049186..6b78d18db0 100644 --- a/lms/xmodule_namespace.py +++ b/lms/xmodule_namespace.py @@ -1,33 +1,8 @@ """ Namespace that defines fields common to all blocks used in the LMS """ -from xblock.core import Namespace, Boolean, Scope, String, Float -from xmodule.fields import Date, Timedelta - - -class StringyBoolean(Boolean): - """ - Reads strings from JSON as booleans. - - 'true' (case insensitive) return True, other strings return False - Other types are returned unchanged - """ - def from_json(self, value): - if isinstance(value, basestring): - return value.lower() == 'true' - return value - - -class StringyFloat(Float): - """ - Reads values as floats. If the value parses as a float, returns - that, otherwise returns None - """ - def from_json(self, value): - try: - return float(value) - except: - return None +from xblock.core import Namespace, Boolean, Scope, String +from xmodule.fields import Date, Timedelta, StringyFloat, StringyBoolean class LmsNamespace(Namespace):