diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a37f898b..5b473d88 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,14 @@ Unreleased * +0.17.1 - 2025-11-14 +******************** + +Fixed +===== + +* Avoid circular import of AuthzEnforcer. + 0.17.0 - 2025-11-14 ******************** diff --git a/openedx_authz/__init__.py b/openedx_authz/__init__.py index 4e10cf73..db0b2199 100644 --- a/openedx_authz/__init__.py +++ b/openedx_authz/__init__.py @@ -4,6 +4,6 @@ import os -__version__ = "0.17.0" +__version__ = "0.17.1" ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) diff --git a/openedx_authz/engine/enforcer.py b/openedx_authz/engine/enforcer.py index 48358622..cc76d1cb 100644 --- a/openedx_authz/engine/enforcer.py +++ b/openedx_authz/engine/enforcer.py @@ -22,7 +22,6 @@ from django.conf import settings from openedx_authz.engine.adapter import ExtendedAdapter -from openedx_authz.engine.matcher import is_admin_or_superuser_check def libraries_v2_enabled() -> bool: @@ -201,6 +200,9 @@ def _initialize_enforcer(cls) -> SyncedEnforcer: Returns: SyncedEnforcer: Configured Casbin enforcer with adapter and auto-sync """ + # Avoid circular import + from openedx_authz.engine.matcher import is_admin_or_superuser_check # pylint: disable=import-outside-toplevel + db_alias = getattr(settings, "CASBIN_DB_ALIAS", "default") try: diff --git a/openedx_authz/tests/test_imports.py b/openedx_authz/tests/test_imports.py new file mode 100644 index 00000000..e22d79df --- /dev/null +++ b/openedx_authz/tests/test_imports.py @@ -0,0 +1,36 @@ +"""Test module imports.""" +import sys +from unittest import TestCase + + +class TestImports(TestCase): + """Test that imports work correctly.""" + + def setUp(self): + """Remove cached modules to ensure fresh imports and detect circular dependencies. + """ + super().setUp() + + # List of modules to remove from cache to test fresh imports + modules_to_clear = [ + 'openedx_authz.engine.enforcer', + 'openedx_authz.engine.matcher', + 'openedx_authz.engine.adapter', + 'openedx_authz.api', + 'openedx_authz.api.permissions', + 'openedx_authz.api.roles', + 'openedx_authz.api.users', + 'openedx_authz.api.data', + ] + + for module_name in modules_to_clear: + if module_name in sys.modules: + del sys.modules[module_name] + + def test_import_authzenforcer(self): + """Test that AuthzEnforcer can be imported.""" + from openedx_authz.engine.enforcer import AuthzEnforcer # pylint: disable=import-outside-toplevel + try: + self.assertIsNotNone(AuthzEnforcer) + except ImportError as e: + self.fail(f"Failed to import AuthzEnforcer: {e}")