Skip to content

fix: lazy init and infinite recursion fixes#5

Open
vimzoomer wants to merge 2 commits intoapache:masterfrom
vimzoomer:master
Open

fix: lazy init and infinite recursion fixes#5
vimzoomer wants to merge 2 commits intoapache:masterfrom
vimzoomer:master

Conversation

@vimzoomer
Copy link

Hi, I have two fixes for the adapter:

  1. Accessing database in ready is discouraged by Django, since ProxyEnforcer lazy-initializes Casbin anyway, initialization should be removed from CasbinAdapterConfig.
  2. Infinite recursion in __getattribute__(self, name) caused by self.db_alias. Also, If enforcer is imported in testing environment it breaks Django's test runner which calls __class__ on every imported module during test discovery.

- Remove CasbinAdapterConfig initialization in ready
- Fix infinite recursion in __getattribute__
- Prevent test runner crash in testing environment
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Django Casbin adapter to avoid eager database access during app startup and fixes a recursion issue in the lazy-loading proxy enforcer, improving compatibility with Django’s initialization and test discovery behavior.

Changes:

  • Remove AppConfig.ready()-time enforcer initialization to avoid DB access during Django startup.
  • Fix infinite recursion in ProxyEnforcer.__getattribute__ by avoiding self.db_alias attribute lookup.
  • Update README installation instructions to use casbin_adapter in INSTALLED_APPS.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
casbin_adapter/enforcer.py Adjusts lazy-init mechanics, avoids recursion, and exempts __class__ from triggering initialization.
casbin_adapter/apps.py Removes ready() hook that previously initialized the enforcer (and touched the DB) during app startup.
README.md Updates Django installation instructions consistent with removing the custom AppConfig.ready() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

class ProxyEnforcer(Enforcer):
_initialized = False
db_alias = "default"
db_alias = getattr(settings, "CASBIN_DB_ALIAS", "default")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using django.conf.settings at import time is generally acceptable, but can be moved to ready for extra pre-cautions

Comment on lines 45 to 49
def __getattribute__(self, name):
safe_methods = ["__init__", "_load", "_initialized"]
safe_methods = ["__init__", "_load", "_initialized", "__class__"]
if not super().__getattribute__("_initialized") and name not in safe_methods:
initialize_enforcer(self.db_alias)
initialize_enforcer(super().__getattribute__("db_alias"))
if not super().__getattribute__("_initialized"):
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing it properly wouldn't be that easy, currently calling any method from safe_methods obviously won't trigger any errors, same with super().__getattribute__("db_alias")

@vimzoomer vimzoomer force-pushed the master branch 2 times, most recently from 32f9f7a to 70721f8 Compare March 15, 2026 16:36
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@vimzoomer
Copy link
Author

@hsluoyz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants