diff --git a/openedx/core/djangoapps/credit/api.py b/openedx/core/djangoapps/credit/api.py index f29ede92b2..e64abc1f67 100644 --- a/openedx/core/djangoapps/credit/api.py +++ b/openedx/core/djangoapps/credit/api.py @@ -6,7 +6,7 @@ from openedx.core.djangoapps.credit.exceptions import InvalidCreditCourse def set_credit_requirements(course_key, requirements): - """ Add requirements to given course + """Add requirements to given course. Args: course_key(CourseKey): The identifier for course @@ -16,24 +16,22 @@ def set_credit_requirements(course_key, requirements): >>> set_credit_requirements( "course-v1-edX-DemoX-1T2015", [ - { - "namespace": "verification", - "name": "verification", - "criteria": {}, - }, { "namespace": "reverification", - "name": "midterm", + "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", + "display_name": "Assessment 1", "criteria": {}, }, { "namespace": "proctored_exam", - "name": "final", + "name": "i4x://edX/DemoX/proctoring-block/final_uuid", + "display_name": "Final Exam", "criteria": {}, }, { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": {"min_grade": 0.8}, }, ]) @@ -65,7 +63,7 @@ def set_credit_requirements(course_key, requirements): def get_credit_requirements(course_key, namespace=None): - """ Returns the requirements of a given course and namespace + """Get credit eligibility requirements of a given course and namespace. Args: course_key(CourseKey): The identifier for course @@ -76,24 +74,22 @@ def get_credit_requirements(course_key, namespace=None): { requirements = [ - { - "namespace": "verification", - "name": "verification", - "criteria": {}, - }, { "namespace": "reverification", - "name": "midterm", + "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", + "display_name": "Assessment 1", "criteria": {}, }, { "namespace": "proctored_exam", - "name": "final", + "name": "i4x://edX/DemoX/proctoring-block/final_uuid", + "display_name": "Final Exam", "criteria": {}, }, { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": {"min_grade": 0.8}, }, ] @@ -108,6 +104,7 @@ def get_credit_requirements(course_key, namespace=None): { "namespace": requirement.namespace, "name": requirement.name, + "display_name": requirement.display_name, "criteria": requirement.criteria } for requirement in requirements @@ -115,7 +112,8 @@ def get_credit_requirements(course_key, namespace=None): def _get_requirements_to_disable(old_requirements, new_requirements): - """ Returns the ids of CreditRequirement to be disabled that are deleted from the courseware + """Get the ids of 'CreditRequirement' entries to be disabled that are + deleted from the courseware. Args: old_requirements(QuerySet): QuerySet of CreditRequirement @@ -128,6 +126,7 @@ def _get_requirements_to_disable(old_requirements, new_requirements): for old_req in old_requirements: found_flag = False for req in new_requirements: + # check if an already added requirement is modified if req["namespace"] == old_req.namespace and req["name"] == old_req.name: found_flag = True break @@ -137,7 +136,7 @@ def _get_requirements_to_disable(old_requirements, new_requirements): def _validate_requirements(requirements): - """ Validate the requirements + """Validate the requirements. Args: requirements(list): List of requirements @@ -152,6 +151,8 @@ def _validate_requirements(requirements): invalid_params.append("namespace") if not requirement.get("name"): invalid_params.append("name") + if not requirement.get("display_name"): + invalid_params.append("display_name") if "criteria" not in requirement: invalid_params.append("criteria") diff --git a/openedx/core/djangoapps/credit/exceptions.py b/openedx/core/djangoapps/credit/exceptions.py index c7cba03f42..2ada6c3f1f 100644 --- a/openedx/core/djangoapps/credit/exceptions.py +++ b/openedx/core/djangoapps/credit/exceptions.py @@ -1,11 +1,17 @@ -""" This module contains the exceptions raised in credit course requirements """ +""" +This module contains the exceptions raised in credit course requirements. +""" class InvalidCreditRequirements(Exception): - """ The exception occurs when the requirement dictionary has invalid format. """ + """ + The exception occurs when the requirement dictionary has invalid format. + """ pass class InvalidCreditCourse(Exception): - """ The exception occurs when the the course is not marked as a Credit Course. """ + """ + The exception occurs when the the course is not marked as a Credit Course. + """ pass diff --git a/openedx/core/djangoapps/credit/migrations/0004_auto__add_field_creditrequirement_display_name.py b/openedx/core/djangoapps/credit/migrations/0004_auto__add_field_creditrequirement_display_name.py new file mode 100644 index 0000000000..7c49053dbe --- /dev/null +++ b/openedx/core/djangoapps/credit/migrations/0004_auto__add_field_creditrequirement_display_name.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding field 'CreditRequirement.display_name' + db.add_column('credit_creditrequirement', 'display_name', + self.gf('django.db.models.fields.CharField')(default='', max_length=255), + keep_default=False) + + + def backwards(self, orm): + # Deleting field 'CreditRequirement.display_name' + db.delete_column('credit_creditrequirement', 'display_name') + + + models = { + 'credit.creditcourse': { + 'Meta': {'object_name': 'CreditCourse'}, + 'course_key': ('xmodule_django.models.CourseKeyField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'credit.crediteligibility': { + 'Meta': {'unique_together': "(('username', 'course'),)", 'object_name': 'CreditEligibility'}, + 'course': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'eligibilities'", 'to': "orm['credit.CreditCourse']"}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'provider': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'eligibilities'", 'to': "orm['credit.CreditProvider']"}), + 'username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}) + }, + 'credit.creditprovider': { + 'Meta': {'object_name': 'CreditProvider'}, + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'provider_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}) + }, + 'credit.creditrequirement': { + 'Meta': {'unique_together': "(('namespace', 'name', 'course'),)", 'object_name': 'CreditRequirement'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'course': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'credit_requirements'", 'to': "orm['credit.CreditCourse']"}), + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'criteria': ('jsonfield.fields.JSONField', [], {}), + 'display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'namespace': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'credit.creditrequirementstatus': { + 'Meta': {'object_name': 'CreditRequirementStatus'}, + 'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}), + 'reason': ('jsonfield.fields.JSONField', [], {'default': '{}'}), + 'requirement': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'statuses'", 'to': "orm['credit.CreditRequirement']"}), + 'status': ('django.db.models.fields.CharField', [], {'max_length': '32'}), + 'username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}) + } + } + + complete_apps = ['credit'] \ No newline at end of file diff --git a/openedx/core/djangoapps/credit/models.py b/openedx/core/djangoapps/credit/models.py index c4640144ba..7e71cedc71 100644 --- a/openedx/core/djangoapps/credit/models.py +++ b/openedx/core/djangoapps/credit/models.py @@ -19,14 +19,16 @@ log = logging.getLogger(__name__) class CreditCourse(models.Model): - """Model for tracking a credit course.""" + """ + Model for tracking a credit course. + """ course_key = CourseKeyField(max_length=255, db_index=True, unique=True) enabled = models.BooleanField(default=False) @classmethod def is_credit_course(cls, course_key): - """ Check that given course is credit or not + """Check that given course is credit or not. Args: course_key(CourseKey): The course identifier @@ -38,7 +40,7 @@ class CreditCourse(models.Model): @classmethod def get_credit_course(cls, course_key): - """ Get the credit course if exists for the given course_key + """Get the credit course if exists for the given 'course_key'. Args: course_key(CourseKey): The course identifier @@ -65,28 +67,36 @@ class CreditProvider(TimeStampedModel): class CreditRequirement(TimeStampedModel): """This model represents a credit requirement. - Each requirement is uniquely identified by a `namespace` and a `name`. CreditRequirements - also include a `criteria` dictionary, the format of which varies by the type of requirement. - The criteria dictionary provides additional information clients may need to determine - whether a user has satisfied the requirement. + Each requirement is uniquely identified by its 'namespace' and + 'name' fields. + The 'name' field stores the unique name or location (in case of XBlock) + for a requirement, which serves as the unique identifier for that + requirement. + The 'display_name' field stores the display name of the requirement. + The 'criteria' field dictionary provides additional information, clients + may need to determine whether a user has satisfied the requirement. """ course = models.ForeignKey(CreditCourse, related_name="credit_requirements") namespace = models.CharField(max_length=255) name = models.CharField(max_length=255) + display_name = models.CharField(max_length=255) criteria = JSONField() active = models.BooleanField(default=True) class Meta(object): - """Model metadata""" + """ + Model metadata. + """ unique_together = ('namespace', 'name', 'course') @classmethod def add_or_update_course_requirement(cls, credit_course, requirement): - """ Add requirement to a given course + """Add requirement to a given course. + Args: - credit_course(CreditCourse): The identifier for credit course course - requirement(dict): requirement dict to be added + credit_course(CreditCourse): The identifier for credit course + requirement(dict): Requirement dict to be added Returns: (CreditRequirement, created) tuple @@ -96,6 +106,7 @@ class CreditRequirement(TimeStampedModel): course=credit_course, namespace=requirement["namespace"], name=requirement["name"], + display_name=requirement["display_name"], defaults={"criteria": requirement["criteria"], "active": True} ) if not created: @@ -107,11 +118,11 @@ class CreditRequirement(TimeStampedModel): @classmethod def get_course_requirements(cls, course_key, namespace=None): - """ Get credit requirements of a given course + """Get credit requirements of a given course. Args: course_key(CourseKey): The identifier for a course - namespace(str): namespace of credit course requirements + namespace(str): Namespace of credit course requirements Returns: QuerySet of CreditRequirement model @@ -123,7 +134,7 @@ class CreditRequirement(TimeStampedModel): @classmethod def disable_credit_requirements(cls, requirement_ids): - """ Mark the given requirements inactive + """Mark the given requirements inactive. Args: requirement_ids(list): List of ids @@ -176,5 +187,7 @@ class CreditEligibility(TimeStampedModel): provider = models.ForeignKey(CreditProvider, related_name="eligibilities") class Meta(object): - """Model metadata""" + """ + Model metadata. + """ unique_together = ('username', 'course') diff --git a/openedx/core/djangoapps/credit/signals.py b/openedx/core/djangoapps/credit/signals.py index 10bea0bf71..2c9fcb12da 100644 --- a/openedx/core/djangoapps/credit/signals.py +++ b/openedx/core/djangoapps/credit/signals.py @@ -1,4 +1,6 @@ -"""This file contains receivers of course publication signals.""" +""" +This file contains receivers of course publication signals. +""" from django.dispatch import receiver @@ -7,11 +9,12 @@ from xmodule.modulestore.django import SignalHandler @receiver(SignalHandler.course_published) def listen_for_course_publish(sender, course_key, **kwargs): # pylint: disable=unused-argument - """ - Receives signal and kicks off celery task to update the course requirements. + """Receive 'course_published' signal and kick off a celery task to update + the credit course requirements. """ - # import here, because signal is registered at startup, but items in tasks are not yet able to be loaded + # Import here, because signal is registered at startup, but items in tasks + # are not yet able to be loaded from .tasks import update_course_requirements update_course_requirements.delay(unicode(course_key)) diff --git a/openedx/core/djangoapps/credit/tasks.py b/openedx/core/djangoapps/credit/tasks.py index be27d7663b..d2bc418273 100644 --- a/openedx/core/djangoapps/credit/tasks.py +++ b/openedx/core/djangoapps/credit/tasks.py @@ -1,4 +1,6 @@ -""" This file contains celery tasks for credit course views """ +""" +This file contains celery tasks for credit course views. +""" from django.conf import settings @@ -55,20 +57,20 @@ def _get_course_credit_requirements(course): List of minimum_grade_credit and ICRV requirements """ - icrv_requirements = _get_credit_course_requirement_xblocks(course) + credit_xblock_requirements = _get_credit_course_requirement_xblocks(course) min_grade_requirement = _get_min_grade_requirement(course) - credit_requirements = icrv_requirements + min_grade_requirement + credit_requirements = credit_xblock_requirements + min_grade_requirement return credit_requirements def _get_min_grade_requirement(course): - """Returns the list of minimum_grade_credit requirements for the given course. + """Get list of 'minimum_grade_credit' requirement for the given course. Args: course(Course): The course object Raises: - AttributeError if the course has not minimum_grade_credit attribute + AttributeError if the course has not 'minimum_grade_credit' attribute Returns: The list of minimum_grade_credit requirements @@ -80,6 +82,7 @@ def _get_min_grade_requirement(course): { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": { "min_grade": getattr(course, "minimum_grade_credit") } @@ -91,7 +94,7 @@ def _get_min_grade_requirement(course): def _get_credit_course_requirement_xblocks(course): # pylint: disable=invalid-name - """Generates a course structure dictionary for the specified course. + """Generate a course structure dictionary for the specified course. Args: course(Course): The course object @@ -109,23 +112,25 @@ def _get_credit_course_requirement_xblocks(course): # pylint: disable=invalid-n block = { "namespace": curr_block.get_credit_requirement_namespace(), "name": curr_block.get_credit_requirement_name(), + "display_name": curr_block.get_credit_requirement_display_name(), "criteria": "" } requirements_blocks.append(block) - # Add this blocks children to the stack so that we can traverse them as well. + # Add the children of current block to the stack so that we can + # traverse them as well. blocks_stack.extend(children) return requirements_blocks def _is_credit_requirement(xblock): - """Check if the given xblock is a credit requirement. + """Check if the given XBlock is a credit requirement. Args: - xblock(XBlock): The given xblock object + xblock(XBlock): The given XBlock object Returns: - True if xblock is a credit requirement else False + True if XBlock is a credit requirement else False """ is_credit_requirement = False diff --git a/openedx/core/djangoapps/credit/tests/test_api.py b/openedx/core/djangoapps/credit/tests/test_api.py index dadd5a4493..0dcd52bdb3 100644 --- a/openedx/core/djangoapps/credit/tests/test_api.py +++ b/openedx/core/djangoapps/credit/tests/test_api.py @@ -1,7 +1,11 @@ -""" Tests for credit course api """ +""" +Tests for credit course api. +""" + import ddt from opaque_keys.edx.keys import CourseKey + from openedx.core.djangoapps.credit.api import ( get_credit_requirements, set_credit_requirements, _get_requirements_to_disable ) @@ -12,7 +16,9 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @ddt.ddt class ApiTestCases(ModuleStoreTestCase): - """ Tests for credit course api """ + """ + Tests for credit course api. + """ def setUp(self, **kwargs): super(ApiTestCases, self).setUp() @@ -39,6 +45,7 @@ class ApiTestCases(ModuleStoreTestCase): { "namespace": "grade", "name": "grade", + "display_name": "Grade" } ] ) @@ -48,25 +55,34 @@ class ApiTestCases(ModuleStoreTestCase): set_credit_requirements(self.course_key, requirements) def test_set_credit_requirements_invalid_course(self): + """Test that 'InvalidCreditCourse' exception is raise if we try to + set credit requirements for a non credit course. + """ requirements = [ { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": {} } ] with self.assertRaises(InvalidCreditCourse): set_credit_requirements(self.course_key, requirements) + self.add_credit_course(enabled=False) with self.assertRaises(InvalidCreditCourse): set_credit_requirements(self.course_key, requirements) def test_set_get_credit_requirements(self): + """Test that if same requirement is added multiple times + then it is added only one time and update for next all iterations. + """ self.add_credit_course() requirements = [ { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": { "min_grade": 0.8 } @@ -74,27 +90,26 @@ class ApiTestCases(ModuleStoreTestCase): { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": { - "min_grade": 0.8 + "min_grade": 0.9 } } ] set_credit_requirements(self.course_key, requirements) self.assertEqual(len(get_credit_requirements(self.course_key)), 1) + # now verify that the saved requirement has values of last requirement + # from all same requirements + self.assertEqual(get_credit_requirements(self.course_key)[0], requirements[1]) + def test_disable_credit_requirements(self): self.add_credit_course() requirements = [ { "namespace": "grade", "name": "grade", - "criteria": { - "min_grade": 0.8 - } - }, - { - "namespace": "grade", - "name": "grade", + "display_name": "Grade", "criteria": { "min_grade": 0.8 } @@ -106,12 +121,14 @@ class ApiTestCases(ModuleStoreTestCase): requirements = [ { "namespace": "reverification", - "name": "midterm", + "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", + "display_name": "Assessment 1", "criteria": {} } ] set_credit_requirements(self.course_key, requirements) self.assertEqual(len(get_credit_requirements(self.course_key)), 1) + grade_req = CreditRequirement.objects.filter(namespace="grade", name="grade") self.assertEqual(len(grade_req), 1) self.assertEqual(grade_req[0].active, False) @@ -122,13 +139,7 @@ class ApiTestCases(ModuleStoreTestCase): { "namespace": "grade", "name": "grade", - "criteria": { - "min_grade": 0.8 - } - }, - { - "namespace": "grade", - "name": "grade", + "display_name": "Grade", "criteria": { "min_grade": 0.8 } @@ -142,7 +153,8 @@ class ApiTestCases(ModuleStoreTestCase): requirements = [ { "namespace": "reverification", - "name": "midterm", + "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", + "display_name": "Assessment 1", "criteria": {} } ] @@ -154,13 +166,15 @@ class ApiTestCases(ModuleStoreTestCase): { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": { "min_grade": 0.8 } }, { "namespace": "reverification", - "name": "midterm", + "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", + "display_name": "Assessment 1", "criteria": {} } ] @@ -168,8 +182,9 @@ class ApiTestCases(ModuleStoreTestCase): self.assertEqual(len(requirements_to_disabled), 0) def add_credit_course(self, enabled=True): - """ Mark the course as a credit """ - + """ + Mark the course as a credit. + """ credit_course = CreditCourse(course_key=self.course_key, enabled=enabled) credit_course.save() return credit_course diff --git a/openedx/core/djangoapps/credit/tests/test_models.py b/openedx/core/djangoapps/credit/tests/test_models.py index fccdc05566..9d6d4ef9d4 100644 --- a/openedx/core/djangoapps/credit/tests/test_models.py +++ b/openedx/core/djangoapps/credit/tests/test_models.py @@ -1,15 +1,20 @@ -""" Tests for credit course models """ +""" +Tests for credit course models. +""" import ddt from opaque_keys.edx.keys import CourseKey + from openedx.core.djangoapps.credit.models import CreditCourse, CreditRequirement from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @ddt.ddt class ModelTestCases(ModuleStoreTestCase): - """ Tests for credit course models """ + """ + Tests for credit course models. + """ def setUp(self, **kwargs): super(ModelTestCases, self).setUp() @@ -28,6 +33,7 @@ class ModelTestCases(ModuleStoreTestCase): requirement = { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": { "min_grade": 0.8 } @@ -43,6 +49,7 @@ class ModelTestCases(ModuleStoreTestCase): requirement = { "namespace": "grade", "name": "grade", + "display_name": "Grade", "criteria": { "min_grade": 0.8 } @@ -52,9 +59,10 @@ class ModelTestCases(ModuleStoreTestCase): self.assertEqual(created, True) requirement = { - "namespace": "icrv", - "name": "midterm", - "criteria": "" + "namespace": "reverification", + "name": "i4x://edX/DemoX/edx-reverification-block/assessment_uuid", + "display_name": "Assessment 1", + "criteria": {} } credit_req, created = CreditRequirement.add_or_update_course_requirement(credit_course, requirement) self.assertEqual(credit_course, credit_req.course) @@ -62,6 +70,7 @@ class ModelTestCases(ModuleStoreTestCase): requirements = CreditRequirement.get_course_requirements(self.course_key) self.assertEqual(len(requirements), 2) + requirements = CreditRequirement.get_course_requirements(self.course_key, namespace="grade") self.assertEqual(len(requirements), 1) diff --git a/openedx/core/djangoapps/credit/tests/test_tasks.py b/openedx/core/djangoapps/credit/tests/test_tasks.py index a0cbbae6a4..cef3605920 100644 --- a/openedx/core/djangoapps/credit/tests/test_tasks.py +++ b/openedx/core/djangoapps/credit/tests/test_tasks.py @@ -1,4 +1,6 @@ -""" Tests for credit course tasks """ +""" +Tests for credit course tasks. +""" import mock from datetime import datetime @@ -13,16 +15,17 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory class TestTaskExecution(ModuleStoreTestCase): - """ - Set of tests to ensure that the task code will do the right thing when - executed directly. The test course gets created without the listeners - being present, which allows us to ensure that when the listener is - executed, it is done as expected. + """Set of tests to ensure that the task code will do the right thing when + executed directly. + + The test course gets created without the listeners being present, which + allows us to ensure that when the listener is executed, it is done as + expected. """ def mocked_set_credit_requirements(course_key, requirements): # pylint: disable=no-self-argument, unused-argument - """ - Used as a side effect when mocking `verify_student.ssencrypt.has_valid_signature`. + """Used as a side effect when mocking method credit api method + 'set_credit_requirements'. """ raise InvalidCreditRequirements @@ -46,8 +49,7 @@ class TestTaskExecution(ModuleStoreTestCase): def test_task_adding_requirements_invalid_course(self): """ - Make sure that the receiver correctly fires off the task when - invoked by signal + Test that credit requirements cannot be added for non credit course. """ requirements = get_credit_requirements(self.course.id) self.assertEqual(len(requirements), 0) @@ -57,9 +59,10 @@ class TestTaskExecution(ModuleStoreTestCase): self.assertEqual(len(requirements), 0) def test_task_adding_requirements(self): - """ + """Test that credit requirements are added properly for credit course. + Make sure that the receiver correctly fires off the task when - invoked by signal + invoked by signal. """ self.add_credit_course(self.course.id) requirements = get_credit_requirements(self.course.id) @@ -70,9 +73,8 @@ class TestTaskExecution(ModuleStoreTestCase): self.assertEqual(len(requirements), 1) def test_task_adding_icrv_requirements(self): - """ - Make sure that the receiver correctly fires off the task when - invoked by signal + """Make sure that the receiver correctly fires off the task when + invoked by signal. """ self.add_credit_course(self.course.id) self.add_icrv_xblock() @@ -90,7 +92,9 @@ class TestTaskExecution(ModuleStoreTestCase): ) ) def test_retry(self): - """ + """Test that adding credit requirements is retried when + 'InvalidCreditRequirements' exception is raised. + Make sure that the receiver correctly fires off the task when invoked by signal """ @@ -103,10 +107,10 @@ class TestTaskExecution(ModuleStoreTestCase): self.assertEqual(len(requirements), 0) def add_credit_course(self, course_key): - """ Add the course as a credit + """Add the course as a credit. Args: - course_key(CourseKey): identifier for the course + course_key(CourseKey): Identifier for the course Returns: CreditCourse object added diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index 4862d9779d..c0ab73cca5 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -50,7 +50,7 @@ git+https://github.com/hmarr/django-debug-toolbar-mongo.git@b0686a76f1ce3532088c git+https://github.com/edx/edx-lint.git@ed8c8d2a0267d4d42f43642d193e25f8bd575d9b#egg=edx_lint==0.2.3 -e git+https://github.com/edx/xblock-utils.git@db22bc40fd2a75458a3c66d057f88aff5a7383e6#egg=xblock-utils -e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive --e git+https://github.com/edx/edx-reverification-block.git@03da85753d5f563a22c1282c0e89fcb2e828b8c1#egg=edx-reverification-block +-e git+https://github.com/edx/edx-reverification-block.git@6e2834c5f7e998ad9b81170e7ceb4d8a64900eb0#egg=edx-reverification-block git+https://github.com/edx/ecommerce-api-client.git@1.0.0#egg=ecommerce-api-client==1.0.0 # Third Party XBlocks