diff --git a/milestones/services.py b/milestones/services.py new file mode 100644 index 00000000..b14fb359 --- /dev/null +++ b/milestones/services.py @@ -0,0 +1,46 @@ +""" +A wrapper class around requested methods exposed in api.py +""" + +import types + +from milestones import api as milestones_api + + +class MilestonesService(object): # pylint: disable=too-few-public-methods + """ + An xBlock service for xBlocks to talk to the Milestones subsystem. + + NOTE: This is a Singleton class. We should only have one instance of it! + """ + + _instance = None + + REQUESTED_FUNCTIONS = [ + 'get_course_content_milestones', + ] + + def __new__(cls, *args, **kwargs): + """ + This is the class factory to make sure this is a Singleton + """ + if not cls._instance: + cls._instance = super(MilestonesService, cls).__new__(cls, *args, **kwargs) + return cls._instance + + def __init__(self): + """ + Class initializer, which just inspects the libraries and exposes the same functions + listed in REQUESTED_FUNCTIONS + """ + self._bind_to_requested_functions() + + def _bind_to_requested_functions(self): + """ + bind module functions. Since we use underscores to mean private methods, let's exclude those. + """ + for attr_name in self.REQUESTED_FUNCTIONS: + attr = getattr(milestones_api, attr_name, None) + if isinstance(attr, types.FunctionType) and not attr_name.startswith('_'): + if not hasattr(self, attr_name): + setattr(self, attr_name, attr) diff --git a/milestones/tests/test_services.py b/milestones/tests/test_services.py new file mode 100644 index 00000000..08dd711f --- /dev/null +++ b/milestones/tests/test_services.py @@ -0,0 +1,37 @@ +""" +Test for the xBlock service +""" + +import unittest +import types + +from milestones.services import MilestonesService +from milestones import api as milestones_api + + +class TestMilestonesService(unittest.TestCase): # pylint: disable=too-many-public-methods + """ + Tests for MilestonesService + """ + def test_basic(self): + """ + See if the MilestonesService exposes the expected methods + """ + + service = MilestonesService() + + for attr_name in dir(milestones_api): + attr = getattr(milestones_api, attr_name, None) + if isinstance(attr, types.FunctionType) and not attr_name.startswith('_'): + if attr_name in MilestonesService.REQUESTED_FUNCTIONS: + self.assertTrue(hasattr(service, attr_name)) + else: + self.assertFalse(hasattr(service, attr_name)) + + def test_singleton(self): + """ + Test to make sure the MilestonesService is a singleton. + """ + service1 = MilestonesService() + service2 = MilestonesService() + self.assertIs(service1, service2) diff --git a/setup.py b/setup.py index 60a9cdaf..d0602bf7 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ setup( name='edx-milestones', - version='0.1.8', + version='0.1.9', description='Significant events module for Open edX', long_description=open('README.md').read(), author='edX',