Skip to content

Commit 37dcb63

Browse files
committed
Fix settings extra handlers str resolution
1 parent 9cb5d25 commit 37dcb63

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

drf_simple_api_errors/extra_handlers.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313
from rest_framework import exceptions
1414

1515

16-
def set_default_detail_to_formatted_exc_default_code(
17-
exc: exceptions.APIException,
18-
) -> exceptions.APIException:
16+
def set_default_detail_to_formatted_exc_default_code(exc: Exception) -> Exception:
1917
"""
2018
Formats the `default_detail` for specific DRF exceptions
2119
by setting it to a human-readable string based on the exception `default_code`.

drf_simple_api_errors/handlers.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
- `get_response_headers`: Gets the response headers for the given exception.
1111
"""
1212

13-
from typing import Dict, Union
13+
import importlib
14+
from typing import Callable, Dict, Union
1415

1516
from django.core.exceptions import (
1617
PermissionDenied,
@@ -23,27 +24,57 @@
2324
from drf_simple_api_errors import extra_handlers
2425
from drf_simple_api_errors.settings import api_settings
2526

27+
DEFAULT_EXTRA_HANDLERS = [
28+
extra_handlers.set_default_detail_to_formatted_exc_default_code
29+
]
30+
"""Default extra handlers to always apply."""
31+
2632

2733
def apply_extra_handlers(exc: Exception):
2834
"""
2935
Apply any extra exception handlers defined in the settings.
3036
3137
Args:
3238
exc (Exception): The exception to handle.
39+
40+
Returns:
41+
int: The number of handlers applied (this is mainly for unit testing).
3342
"""
3443
# Get the default extra handlers and the ones defined in the settings.
3544
# The default handlers are always applied to ensure that exceptions
3645
# are formatted correctly.
37-
default_extra_handlers = [
38-
extra_handlers.set_default_detail_to_formatted_exc_default_code
39-
]
40-
settings_extra_handlers = api_settings.EXTRA_HANDLERS
41-
42-
extra_handlers_to_apply = default_extra_handlers + settings_extra_handlers
46+
# Resolve the settings extra handlers.
47+
# The settings extra handlers is a list of strings representing
48+
# the import path to the handler function.
49+
# This allows for lazy loading of the handlers.
50+
settings_extra_handlers: list[Callable] = []
51+
for handler_path in api_settings.EXTRA_HANDLERS or []:
52+
if not isinstance(handler_path, str):
53+
raise ValueError(
54+
f"EXTRA_HANDLERS must be a list of strings. Found: {type(handler_path)}"
55+
)
56+
57+
module_path, func_name = handler_path.rsplit(".", 1)
58+
try:
59+
module = importlib.import_module(module_path)
60+
except ModuleNotFoundError:
61+
raise ValueError(f"Path {handler_path} not found.")
62+
63+
func = getattr(module, func_name, None)
64+
if func is None:
65+
raise ValueError(f"Handler {func_name} not found.")
66+
if not callable(func):
67+
raise ValueError(f"Handler {func_name} is not callable.")
68+
else:
69+
settings_extra_handlers.append(func)
70+
71+
extra_handlers_to_apply = DEFAULT_EXTRA_HANDLERS + settings_extra_handlers
4372
if extra_handlers_to_apply:
4473
for handler in extra_handlers_to_apply:
4574
handler(exc)
4675

76+
return len(extra_handlers_to_apply)
77+
4778

4879
def convert_django_exc_to_drf_api_exc(
4980
exc: Exception,

0 commit comments

Comments
 (0)