Skip to content

Commit 4916c8f

Browse files
chore: implement format command for easier quality management
1 parent c911424 commit 4916c8f

22 files changed

Lines changed: 682 additions & 215 deletions

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ upgrade: ## update the requirements/*.txt files with the latest packages satisfy
5858
quality: ## check coding style with pycodestyle and pylint
5959
tox -e quality
6060

61+
format: ## format code with black and isort
62+
black openedx_authz tests
63+
isort openedx_authz tests
64+
6165
pii_check: ## check for PII annotations on all Django models
6266
tox -e pii_check
6367

openedx_authz/api/roles.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,5 +413,10 @@ def get_subjects_for_role(role: RoleData) -> list[SubjectData]:
413413
"""
414414
enforcer = AuthzEnforcer.get_enforcer()
415415
enforcer.load_policy()
416-
policies = enforcer.get_filtered_grouping_policy(GroupingPolicyIndex.ROLE.value, role.namespaced_key)
417-
return [SubjectData(namespaced_key=policy[GroupingPolicyIndex.SUBJECT.value]) for policy in policies]
416+
policies = enforcer.get_filtered_grouping_policy(
417+
GroupingPolicyIndex.ROLE.value, role.namespaced_key
418+
)
419+
return [
420+
SubjectData(namespaced_key=policy[GroupingPolicyIndex.SUBJECT.value])
421+
for policy in policies
422+
]

openedx_authz/api/users.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737
]
3838

3939

40-
def assign_role_to_user_in_scope(user_external_key: str, role_external_key: str, scope_external_key: str) -> bool:
40+
def assign_role_to_user_in_scope(
41+
user_external_key: str, role_external_key: str, scope_external_key: str
42+
) -> bool:
4143
"""Assign a role to a user in a specific scope.
4244
4345
Args:
@@ -55,7 +57,9 @@ def assign_role_to_user_in_scope(user_external_key: str, role_external_key: str,
5557
)
5658

5759

58-
def batch_assign_role_to_users_in_scope(users: list[str], role_external_key: str, scope_external_key: str):
60+
def batch_assign_role_to_users_in_scope(
61+
users: list[str], role_external_key: str, scope_external_key: str
62+
):
5963
"""Assign a role to multiple users in a specific scope.
6064
6165
Args:
@@ -71,7 +75,9 @@ def batch_assign_role_to_users_in_scope(users: list[str], role_external_key: str
7175
)
7276

7377

74-
def unassign_role_from_user(user_external_key: str, role_external_key: str, scope_external_key: str):
78+
def unassign_role_from_user(
79+
user_external_key: str, role_external_key: str, scope_external_key: str
80+
):
7581
"""Unassign a role from a user in a specific scope.
7682
7783
Args:
@@ -89,7 +95,9 @@ def unassign_role_from_user(user_external_key: str, role_external_key: str, scop
8995
)
9096

9197

92-
def batch_unassign_role_from_users(users: list[str], role_external_key: str, scope_external_key: str):
98+
def batch_unassign_role_from_users(
99+
users: list[str], role_external_key: str, scope_external_key: str
100+
):
93101
"""Unassign a role from multiple users in a specific scope.
94102
95103
Args:
@@ -117,7 +125,9 @@ def get_user_role_assignments(user_external_key: str) -> list[RoleAssignmentData
117125
return get_subject_role_assignments(UserData(external_key=user_external_key))
118126

119127

120-
def get_user_role_assignments_in_scope(user_external_key: str, scope_external_key: str) -> list[RoleAssignmentData]:
128+
def get_user_role_assignments_in_scope(
129+
user_external_key: str, scope_external_key: str
130+
) -> list[RoleAssignmentData]:
121131
"""Get the roles assigned to a user in a specific scope.
122132
123133
Args:
@@ -162,7 +172,9 @@ def get_all_user_role_assignments_in_scope(
162172
Returns:
163173
list[RoleAssignmentData]: A list of user role assignments and all their metadata in the specified scope.
164174
"""
165-
return get_all_subject_role_assignments_in_scope(ScopeData(external_key=scope_external_key))
175+
return get_all_subject_role_assignments_in_scope(
176+
ScopeData(external_key=scope_external_key)
177+
)
166178

167179

168180
def is_user_allowed(

openedx_authz/engine/adapter.py

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

79-
def load_filtered_policy(self, model: Model, filter: Filter) -> None: # pylint: disable=redefined-builtin
79+
def load_filtered_policy(
80+
self, model: Model, filter: Filter
81+
) -> None: # pylint: disable=redefined-builtin
8082
"""
8183
Load policy rules from storage with filtering applied.
8284
@@ -99,7 +101,9 @@ def load_filtered_policy(self, model: Model, filter: Filter) -> None: # pylint:
99101
for line in filtered_queryset:
100102
persist.load_policy_line(str(line), model)
101103

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

openedx_authz/engine/enforcer.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,19 @@ def _initialize_enforcer() -> FastEnforcer:
9191
# issues when the app is not fully loaded (e.g., while pulling translations, etc.).
9292
initialize_enforcer(db_alias)
9393
except Exception as e:
94-
logger.error(f"Failed to initialize Casbin enforcer with DB alias '{db_alias}': {e}")
94+
logger.error(
95+
f"Failed to initialize Casbin enforcer with DB alias '{db_alias}': {e}"
96+
)
9597
raise
9698

9799
adapter = ExtendedAdapter()
98100
enforcer = FastEnforcer(settings.CASBIN_MODEL, adapter, enable_log=True)
99101
enforcer.enable_auto_save(True)
100102

101103
if not Watcher:
102-
logger.warning("Redis configuration not completed successfully. Watcher is disabled.")
104+
logger.warning(
105+
"Redis configuration not completed successfully. Watcher is disabled."
106+
)
103107
return enforcer
104108

105109
try:

openedx_authz/engine/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ def migrate_policy_between_enforcers(
3131

3232
# Load target enforcer policies to check for duplicates
3333
target_enforcer.load_policy()
34-
logger.info(f"Target enforcer has {len(target_enforcer.get_policy())} existing policies before migration.")
34+
logger.info(
35+
f"Target enforcer has {len(target_enforcer.get_policy())} existing policies before migration."
36+
)
3537

3638
# TODO: this operations use the enforcer directly, which may not be ideal
3739
# since we have to load the policy after each addition to avoid duplicates.

openedx_authz/management/commands/load_policies.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ def handle(self, *args, **options):
6969
Raises:
7070
CommandError: If the policy file is not found or loading fails.
7171
"""
72-
policy_file_path, model_file_path = options["policy_file_path"], options["model_file_path"]
72+
policy_file_path, model_file_path = (
73+
options["policy_file_path"],
74+
options["model_file_path"],
75+
)
7376
if policy_file_path is None:
7477
policy_file_path = os.path.join(
7578
ROOT_DIRECTORY, "engine", "config", "authz.policy"
@@ -83,13 +86,25 @@ def handle(self, *args, **options):
8386

8487
if options.get("clear_existing"):
8588
target_enforcer.load_policy()
86-
if click.confirm(click.style('Do you want to delete existing roles? '
87-
'(This will also delete the assignments related to those roles)',
88-
fg='yellow', bold=True), default=False):
89+
if click.confirm(
90+
click.style(
91+
"Do you want to delete existing roles? "
92+
"(This will also delete the assignments related to those roles)",
93+
fg="yellow",
94+
bold=True,
95+
),
96+
default=False,
97+
):
8998
self._delete_existing_roles(target_enforcer)
9099

91-
if click.confirm(click.style('Do you want to delete existing permissions inheritance?',
92-
fg='yellow', bold=True), default=False):
100+
if click.confirm(
101+
click.style(
102+
"Do you want to delete existing permissions inheritance?",
103+
fg="yellow",
104+
bold=True,
105+
),
106+
default=False,
107+
):
93108
self._delete_permissions_inheritance(target_enforcer)
94109

95110
source_enforcer = casbin.Enforcer(model_file_path, policy_file_path)

openedx_authz/rest_api/decorators.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ def _decorator(func_or_class):
3939
SessionAuthenticationAllowInactiveUser,
4040
]
4141
if is_authenticated:
42-
func_or_class.permission_classes = [IsAuthenticated] + getattr(func_or_class, "permission_classes", [])
42+
func_or_class.permission_classes = [IsAuthenticated] + getattr(
43+
func_or_class, "permission_classes", []
44+
)
4345
return func_or_class
4446

4547
return _decorator

openedx_authz/rest_api/utils.py

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ def get_generic_scope(scope: ScopeData) -> ScopeData:
2828
>>> get_generic_scope(scope)
2929
ScopeData(namespaced_key="lib^*")
3030
"""
31-
return ScopeData(namespaced_key=f"{scope.NAMESPACE}{ScopeData.SEPARATOR}{GENERIC_SCOPE_WILDCARD}")
31+
return ScopeData(
32+
namespaced_key=f"{scope.NAMESPACE}{ScopeData.SEPARATOR}{GENERIC_SCOPE_WILDCARD}"
33+
)
3234

3335

3436
def get_user_map(usernames: list[str]) -> dict[str, User]:
@@ -72,7 +74,9 @@ def get_user_by_username_or_email(username_or_email: str) -> User:
7274

7375

7476
def sort_users(
75-
users: list[dict], sort_by: SortField = SortField.USERNAME, order: SortOrder = SortOrder.ASC
77+
users: list[dict],
78+
sort_by: SortField = SortField.USERNAME,
79+
order: SortOrder = SortOrder.ASC,
7680
) -> list[dict]:
7781
"""
7882
Sort users by a given field and order.
@@ -90,16 +94,26 @@ def sort_users(
9094
list[dict]: The sorted users.
9195
"""
9296
if sort_by not in SortField.values():
93-
raise ValueError(f"Invalid field: '{sort_by}'. Must be one of {SortField.values()}")
97+
raise ValueError(
98+
f"Invalid field: '{sort_by}'. Must be one of {SortField.values()}"
99+
)
94100

95101
if order not in SortOrder.values():
96-
raise ValueError(f"Invalid order: '{order}'. Must be one of {SortOrder.values()}")
97-
98-
sorted_users = sorted(users, key=lambda user: (user.get(sort_by) or "").lower(), reverse=order == SortOrder.DESC)
102+
raise ValueError(
103+
f"Invalid order: '{order}'. Must be one of {SortOrder.values()}"
104+
)
105+
106+
sorted_users = sorted(
107+
users,
108+
key=lambda user: (user.get(sort_by) or "").lower(),
109+
reverse=order == SortOrder.DESC,
110+
)
99111
return sorted_users
100112

101113

102-
def filter_users(users: list[dict], search: str | None, roles: list[str] | None) -> list[dict]:
114+
def filter_users(
115+
users: list[dict], search: str | None, roles: list[str] | None
116+
) -> list[dict]:
103117
"""
104118
Filter users by a case-insensitive search string and/or by roles.
105119
@@ -117,7 +131,10 @@ def filter_users(users: list[dict], search: str | None, roles: list[str] | None)
117131
filtered_users = []
118132
for user in users:
119133
if search:
120-
matches_search = any(search in (user.get(field) or "").lower() for field in SearchField.values())
134+
matches_search = any(
135+
search in (user.get(field) or "").lower()
136+
for field in SearchField.values()
137+
)
121138
if not matches_search:
122139
continue
123140

openedx_authz/rest_api/v1/fields.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ class CommaSeparatedListField(serializers.CharField):
88

99
def to_internal_value(self, data):
1010
"""Convert string separated by commas to list of unique items preserving order"""
11-
return list(dict.fromkeys(item.strip().lower() for item in data.split(",") if item.strip()))
11+
return list(
12+
dict.fromkeys(
13+
item.strip().lower() for item in data.split(",") if item.strip()
14+
)
15+
)
1216

1317
def to_representation(self, value):
1418
"""Convert list to string separated by commas"""

0 commit comments

Comments
 (0)