Skip to content

Commit 3593be0

Browse files
refactor: address quality issues
1 parent bf7e447 commit 3593be0

17 files changed

Lines changed: 86 additions & 99 deletions

File tree

openedx_authz/api/data.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from opaque_keys import InvalidKeyError
88
from opaque_keys.edx.locator import LibraryLocatorV2
99

10-
1110
AUTHZ_POLICY_ATTRIBUTES_SEPARATOR = "^"
1211

1312

@@ -77,14 +76,14 @@ def __attrs_post_init__(self):
7776
class ScopeMeta(type):
7877
"""Metaclass for ScopeData to handle dynamic subclass instantiation based on namespace."""
7978

80-
_scope_registry: ClassVar[dict[str, Type["ScopeData"]]] = {}
79+
scope_registry: ClassVar[dict[str, Type["ScopeData"]]] = {}
8180

8281
def __init__(cls, name, bases, attrs):
8382
"""Initialize the metaclass and register subclasses."""
8483
super().__init__(name, bases, attrs)
85-
if not hasattr(cls, "_scope_registry"):
86-
cls._scope_registry = {}
87-
cls._scope_registry[cls.NAMESPACE] = cls
84+
if not hasattr(cls, "scope_registry"):
85+
cls.scope_registry = {}
86+
cls.scope_registry[cls.NAMESPACE] = cls
8887

8988
def __call__(cls, *args, **kwargs):
9089
"""Instantiate the appropriate subclass based on the namespace in namespaced_key.
@@ -115,7 +114,8 @@ def __call__(cls, *args, **kwargs):
115114

116115
return super().__call__(*args, **kwargs)
117116

118-
def get_subclass_by_namespaced_key(cls, namespaced_key: str) -> Type["ScopeData"]:
117+
@classmethod
118+
def get_subclass_by_namespaced_key(mcs, namespaced_key: str) -> Type["ScopeData"]:
119119
"""Get the appropriate subclass based on the namespace in namespaced_key.
120120
121121
Args:
@@ -126,9 +126,10 @@ def get_subclass_by_namespaced_key(cls, namespaced_key: str) -> Type["ScopeData"
126126
"""
127127
# TODO: Default separator, can't access directly from class so made it a constant
128128
namespace = namespaced_key.split(AUTHZ_POLICY_ATTRIBUTES_SEPARATOR, 1)[0]
129-
return cls._scope_registry.get(namespace, ScopeData)
129+
return mcs.scope_registry.get(namespace, ScopeData)
130130

131-
def get_subclass_by_external_key(cls, external_key: str) -> Type["ScopeData"]:
131+
@classmethod
132+
def get_subclass_by_external_key(mcs, external_key: str) -> Type["ScopeData"]:
132133
"""Get the appropriate subclass based on the format of external_key.
133134
134135
Args:
@@ -145,12 +146,13 @@ def get_subclass_by_external_key(cls, external_key: str) -> Type["ScopeData"]:
145146
# 3. If the namespace is not recognized, we return the base ScopeData class
146147
# 4. The subclass implements a validation method to validate the entire key
147148
namespace = external_key.split(":", 1)[0]
148-
scope_subclass = cls._scope_registry.get(namespace)
149+
scope_subclass = mcs.scope_registry.get(namespace)
149150
if not scope_subclass or not scope_subclass.validate_external_key(external_key):
150151
return ScopeData # Fallback to base class if not found or invalid
151152
return scope_subclass
152153

153-
def validate_external_key(cls, external_key: str) -> bool:
154+
@classmethod
155+
def validate_external_key(mcs, external_key: str) -> bool:
154156
"""Validate the external_key format for the subclass.
155157
156158
Args:
@@ -217,14 +219,14 @@ def validate_external_key(cls, external_key: str) -> bool:
217219
class SubjectMeta(type):
218220
"""Metaclass for SubjectData to handle dynamic subclass instantiation based on namespace."""
219221

220-
_subject_registry: ClassVar[dict[str, Type["SubjectData"]]] = {}
222+
subject_registry: ClassVar[dict[str, Type["SubjectData"]]] = {}
221223

222224
def __init__(cls, name, bases, attrs):
223225
"""Initialize the metaclass and register subclasses."""
224226
super().__init__(name, bases, attrs)
225-
if not hasattr(cls, "_subject_registry"):
226-
cls._subject_registry = {}
227-
cls._subject_registry[cls.NAMESPACE] = cls
227+
if not hasattr(cls, "subject_registry"):
228+
cls.subject_registry = {}
229+
cls.subject_registry[cls.NAMESPACE] = cls
228230

229231
def __call__(cls, *args, **kwargs):
230232
"""Instantiate the appropriate subclass based on the namespace in namespaced_key.
@@ -244,7 +246,8 @@ def __call__(cls, *args, **kwargs):
244246

245247
return super().__call__(*args, **kwargs)
246248

247-
def get_subclass_by_namespaced_key(cls, namespaced_key: str) -> Type["SubjectData"]:
249+
@classmethod
250+
def get_subclass_by_namespaced_key(mcs, namespaced_key: str) -> Type["SubjectData"]:
248251
"""Get the appropriate subclass based on the namespace in namespaced_key.
249252
250253
Args:
@@ -254,7 +257,7 @@ def get_subclass_by_namespaced_key(cls, namespaced_key: str) -> Type["SubjectDat
254257
The subclass of SubjectData corresponding to the namespace, or SubjectData if not found.
255258
"""
256259
namespace = namespaced_key.split(AUTHZ_POLICY_ATTRIBUTES_SEPARATOR, 1)[0]
257-
return cls._subject_registry.get(namespace, SubjectData)
260+
return mcs.subject_registry.get(namespace, SubjectData)
258261

259262

260263
@define

openedx_authz/api/permissions.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@
55
are not explicitly defined, but are inferred from the policy rules.
66
"""
77

8-
from openedx_authz.api.data import (
9-
ActionData,
10-
PermissionData,
11-
PolicyIndex,
12-
ScopeData,
13-
SubjectData,
14-
)
8+
from openedx_authz.api.data import ActionData, PermissionData, PolicyIndex, ScopeData, SubjectData
159
from openedx_authz.engine.enforcer import enforcer
1610

1711
__all__ = [

openedx_authz/api/roles.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@
1616
PolicyIndex,
1717
RoleAssignmentData,
1818
RoleData,
19-
RoleMetadataData,
2019
ScopeData,
2120
SubjectData,
22-
UserData,
2321
)
2422
from openedx_authz.api.permissions import get_permission_from_policy
2523
from openedx_authz.engine.enforcer import enforcer
@@ -163,9 +161,9 @@ def get_role_definitions_in_scope(scope: ScopeData) -> list[RoleData]:
163161
return [
164162
RoleData(
165163
namespaced_key=role,
166-
permissions=permissions_per_role[role]["permissions"],
164+
permissions=permissions["permissions"],
167165
)
168-
for role in permissions_per_role.keys()
166+
for role, permissions in permissions_per_role.items()
169167
]
170168

171169

@@ -336,7 +334,7 @@ def get_subjects_role_assignments_for_role_in_scope(
336334
RoleAssignmentData(
337335
subject=SubjectData(
338336
namespaced_key=subject
339-
), # TODO: I want this to behave like UserData or any other subclass of SubjectData depending on NAMESPACE
337+
),
340338
role=RoleData(
341339
external_key=role.external_key,
342340
permissions=get_permissions_for_roles(role)[role.external_key][

openedx_authz/api/users.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@
99
(e.g., 'user@john_doe').
1010
"""
1111

12-
from openedx_authz.api.data import (
13-
ActionData,
14-
RoleAssignmentData,
15-
RoleData,
16-
ScopeData,
17-
UserData,
18-
)
12+
from openedx_authz.api.data import ActionData, RoleAssignmentData, RoleData, ScopeData, UserData
1913
from openedx_authz.api.permissions import has_permission
2014
from openedx_authz.api.roles import (
2115
assign_role_to_subject_in_scope,

openedx_authz/engine/adapter.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ def is_filtered(self) -> bool:
7676
"""
7777
return True
7878

79-
def load_filtered_policy(
80-
self, model: Model, filter: Filter
81-
) -> None: # pylint: disable=redefined-builtin
79+
def load_filtered_policy(self, model: Model, filter: Filter) -> None: # pylint: disable=redefined-builtin
8280
"""
8381
Load policy rules from storage with filtering applied.
8482
@@ -101,9 +99,7 @@ def load_filtered_policy(
10199
for line in filtered_queryset:
102100
persist.load_policy_line(str(line), model)
103101

104-
def filter_query(
105-
self, queryset: QuerySet, filter: Filter
106-
) -> QuerySet: # pylint: disable=redefined-builtin
102+
def filter_query(self, queryset: QuerySet, filter: Filter) -> QuerySet: # pylint: disable=redefined-builtin
107103
"""
108104
Apply filter criteria to the policy queryset.
109105

openedx_authz/engine/utils.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
"""
66

77
import logging
8-
import os
98

109
from casbin import Enforcer
1110

@@ -25,7 +24,7 @@ def migrate_policy_from_file_to_db(
2524
target_enforcer (Enforcer): The Casbin enforcer instance to migrate policies to (database).
2625
"""
2726
try:
28-
# TODO: need to avoid loading twice the same policies
27+
# Load latest policies from the source enforcer
2928
source_enforcer.load_policy()
3029
policies = source_enforcer.get_policy()
3130
for policy in policies:
@@ -34,7 +33,6 @@ def migrate_policy_from_file_to_db(
3433

3534
for grouping_policy_ptype in GROUPING_POLICY_PTYPES:
3635
try:
37-
source_enforcer.load_policy()
3836
grouping_policies = source_enforcer.get_named_grouping_policy(
3937
grouping_policy_ptype
4038
)

openedx_authz/engine/watcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def create_watcher():
4848
watcher = new_watcher(watcher_options)
4949
logger.info("Redis watcher created successfully")
5050
return watcher
51-
except Exception as e:
51+
except Exception as e: # pylint: disable=broad-exception-caught
5252
logger.error(f"Failed to create Redis watcher: {e}")
5353
return None
5454

openedx_authz/management/commands/load_policies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"""
1111

1212
import casbin
13-
from django.core.management.base import BaseCommand, CommandError
13+
from django.core.management.base import BaseCommand
1414

1515
from openedx_authz.engine.enforcer import enforcer as global_enforcer
1616
from openedx_authz.engine.utils import migrate_policy_from_file_to_db

openedx_authz/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
"""Database models for the authorization framework.
1+
"""
2+
Database models for the authorization framework.
23
34
These models will be used to store additional data about roles and permissions
45
that are not natively supported by Casbin, so as to avoid modifying the Casbin

openedx_authz/settings/test.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import os
66

7-
from django.conf import settings
8-
97
from openedx_authz import ROOT_DIRECTORY
108

119
# Add Casbin configuration

0 commit comments

Comments
 (0)