|
5 | 5 | provide a simpler interface for other services in the Open edX ecosystem. |
6 | 6 | """ |
7 | 7 |
|
| 8 | +# Import data module directly as it has no circular dependencies |
8 | 9 | from openedx_authz.api.data import * |
9 | | -from openedx_authz.api.permissions import * |
10 | | -from openedx_authz.api.roles import * |
11 | | -from openedx_authz.api.users import * |
| 10 | + |
| 11 | +# Lazy import other modules to avoid circular import issues |
| 12 | +# The permissions module imports from engine.enforcer, which creates a circular dependency |
| 13 | +# if imported at module level. Using __getattr__ allows us to defer the import until needed. |
| 14 | + |
| 15 | + |
| 16 | +def __getattr__(name): |
| 17 | + """Lazy import attributes from sub-modules to avoid circular imports. |
| 18 | + |
| 19 | + This function is called when an attribute is not found in the module. |
| 20 | + It allows us to import from sub-modules only when needed, breaking |
| 21 | + the circular dependency chain. |
| 22 | + """ |
| 23 | + # Try importing from each sub-module |
| 24 | + submodules = ['permissions', 'roles', 'users'] |
| 25 | + |
| 26 | + for submodule_name in submodules: |
| 27 | + try: |
| 28 | + submodule = __import__( |
| 29 | + f'openedx_authz.api.{submodule_name}', |
| 30 | + fromlist=[name] |
| 31 | + ) |
| 32 | + if hasattr(submodule, name): |
| 33 | + # Cache the attribute in this module for future access |
| 34 | + globals()[name] = getattr(submodule, name) |
| 35 | + return globals()[name] |
| 36 | + except (ImportError, AttributeError): |
| 37 | + continue |
| 38 | + |
| 39 | + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") |
0 commit comments