diff --git a/CHANGELOG.rst b/CHANGELOG.rst index df64259..e0036f8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,10 @@ Change Log Unreleased ~~~~~~~~~~ +[0.4.0] - 2021-08-06 +~~~~~~~~~~~~~~~~~~~~ +* Expose API methods through `NameAffirmationService`. + [0.3.1] - 2021-08-03 ~~~~~~~~~~~~~~~~~~~~ * Update `MANIFEST.in` to include all directories under `edx_name_affirmation`. diff --git a/edx_name_affirmation/__init__.py b/edx_name_affirmation/__init__.py index 213cea3..0328aff 100644 --- a/edx_name_affirmation/__init__.py +++ b/edx_name_affirmation/__init__.py @@ -2,6 +2,6 @@ Django app housing name affirmation logic. """ -__version__ = '0.3.1' +__version__ = '0.4.0' default_app_config = 'edx_name_affirmation.apps.EdxNameAffirmationConfig' # pylint: disable=invalid-name diff --git a/edx_name_affirmation/services.py b/edx_name_affirmation/services.py new file mode 100644 index 0000000..daf5a99 --- /dev/null +++ b/edx_name_affirmation/services.py @@ -0,0 +1,40 @@ +""" +Name Affirmation Service +""" + +import types + + +class NameAffirmationService: + """ + Service to expose Name Affirmation API methods + """ + + _instance = None + + def __new__(cls, *args, **kwargs): + """ + This is a class factory to make sure this is a Singleton. + """ + if not cls._instance: + cls._instance = super(NameAffirmationService, cls).__new__(cls, *args, **kwargs) + return cls._instance + + def __init__(self): + """ + Class initializer, which just inspects the libraries and exposes the same functions + as a direct pass through. + """ + # pylint: disable=import-outside-toplevel + from edx_name_affirmation import api as edx_name_affirmation_api + self._bind_to_module_functions(edx_name_affirmation_api) + + def _bind_to_module_functions(self, module): + """ + Bind module functions. + """ + for attr_name in dir(module): + attr = getattr(module, attr_name, None) + if isinstance(attr, types.FunctionType): + if not hasattr(self, attr_name): + setattr(self, attr_name, attr) diff --git a/edx_name_affirmation/tests/test_services.py b/edx_name_affirmation/tests/test_services.py new file mode 100644 index 0000000..7605492 --- /dev/null +++ b/edx_name_affirmation/tests/test_services.py @@ -0,0 +1,38 @@ +""" +Tests for NameAffirmation services +""" + +import types + +from django.contrib.auth import get_user_model +from django.test import TestCase + +from edx_name_affirmation import api as edx_name_affirmation_api +from edx_name_affirmation.services import NameAffirmationService + +User = get_user_model() + + +class NameAffirmationServiceTest(TestCase): + """ + Tests for NameAffirmationService + """ + def test_basic(self): + """ + See if the NameAffirmationService exposes the expected methods + """ + + service = NameAffirmationService() + + for attr_name in dir(edx_name_affirmation_api): + attr = getattr(edx_name_affirmation_api, attr_name, None) + if isinstance(attr, types.FunctionType): + self.assertTrue(hasattr(service, attr_name)) + + def test_singleton(self): + """ + Test to make sure the NameAffirmationService is a singleton. + """ + service1 = NameAffirmationService() + service2 = NameAffirmationService() + self.assertIs(service1, service2)