Skip to content

Commit b75320e

Browse files
author
Andy Babic
committed
Add a context modifier registry
1 parent 01431a9 commit b75320e

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

pattern_library/cm_utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
import inspect
3+
from typing import Callable
4+
5+
6+
def accepts_kwarg(func: Callable, kwarg: str) -> bool:
7+
"""
8+
Returns a boolean indicating whether the callable ``func`` has
9+
a signature that accepts the keyword argument ``kwarg``.
10+
"""
11+
signature = inspect.signature(func)
12+
try:
13+
signature.bind_partial(**{kwarg: None})
14+
return True
15+
except TypeError:
16+
return False

pattern_library/context_modifiers.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from collections import defaultdict
2+
from operator import attrgetter
3+
from typing import Callable
4+
5+
from django.core.exceptions import ImproperlyConfigured
6+
7+
from .cm_utils import accepts_kwarg
8+
9+
GENERIC_CM_KEY = "__generic__"
10+
ORDER_ATTR_NAME = "__cm_order"
11+
12+
13+
class ContextModifierRegistry(defaultdict):
14+
def __init__(self):
15+
super().__init__(list)
16+
17+
def register(self, func: Callable, template: str = None, order: int = 0) -> None:
18+
"""
19+
Adds a context modifier to the registry.
20+
"""
21+
if not callable(func):
22+
raise ImproperlyConfigured(
23+
f"Context modifiers must be callables. {func} is a {type(func).__name__}."
24+
)
25+
if not accepts_kwarg(func, "context"):
26+
raise ImproperlyConfigured(
27+
f"Context modifiers must accept a 'context' argument. {func} does not."
28+
)
29+
if not accepts_kwarg(func, "request"):
30+
raise ImproperlyConfigured(
31+
f"Context modifiers must accept a 'request' argument. {func} does not."
32+
)
33+
34+
key = template or GENERIC_CM_KEY
35+
if func not in self[key]:
36+
setattr(func, ORDER_ATTR_NAME, order)
37+
self[key].append(func)
38+
self[key].sort(key=attrgetter(ORDER_ATTR_NAME))
39+
40+
return func
41+
42+
def register_decorator(self, func: Callable = None, **kwargs):
43+
if func is None:
44+
return lambda func: self.register(func, **kwargs)
45+
return self.register(func, **kwargs)
46+
47+
def get_for_template(self, template: str):
48+
modifiers = self[GENERIC_CM_KEY] + self[template]
49+
return sorted(modifiers, key=attrgetter(ORDER_ATTR_NAME))
50+
51+
52+
registry = ContextModifierRegistry()
53+
register_context_modifier = registry.register_decorator

0 commit comments

Comments
 (0)