|
1 |
import itertools
|
|
2 |
|
|
3 |
from django.core.exceptions import ImproperlyConfigured
|
|
4 |
|
|
5 |
from safe_expression import SafeExpression, InvalidExpression
|
|
6 |
|
|
7 |
from ...decorators import to_list
|
|
8 |
|
|
9 |
AUTHORIZED_KEYS = set(('name', 'label', 'condition', 'expression'))
|
|
10 |
|
|
11 |
REQUIRED_KEYS = set(('name', 'expression'))
|
|
12 |
|
|
13 |
UNEXPECTED_KEYS_ERROR = \
|
|
14 |
'{0}: unexpected key(s) {1} in configuration'
|
|
15 |
MISSING_KEYS_ERROR = \
|
|
16 |
'{0}: missing key(s) {1} in configuration'
|
|
17 |
BAD_CONFIG_ERROR = \
|
|
18 |
'{0}: expression attribute source must contain a name and an expression'
|
|
19 |
NOT_CALLABLE_ERROR = \
|
|
20 |
'{0}: function attribute must be callable'
|
|
21 |
|
|
22 |
def config_error(fmt, *args):
|
|
23 |
raise ImproperlyConfigured(fmt.format(__name__, *args))
|
|
24 |
|
|
25 |
@to_list
|
|
26 |
def get_instances(ctx):
|
|
27 |
'''
|
|
28 |
Retrieve instances from settings
|
|
29 |
'''
|
|
30 |
from django.conf import settings
|
|
31 |
all_sources = itertools.chain(
|
|
32 |
getattr(settings, 'ATTRIBUTE_SOURCES', []),
|
|
33 |
ctx.get('__attribute_sources__', []))
|
|
34 |
for kind, d in all_sources:
|
|
35 |
if kind != 'expression':
|
|
36 |
continue
|
|
37 |
if not d.get('__validated'):
|
|
38 |
keys = set(d.keys())
|
|
39 |
if not keys <= AUTHORIZED_KEYS:
|
|
40 |
unexpected = keys - AUTHORIZED_KEYS
|
|
41 |
config_error(UNEXPECTED_KEYS_ERROR, unexpected)
|
|
42 |
if not REQUIRED_KEYS <= keys:
|
|
43 |
missing = REQUIRED_KEYS - keys
|
|
44 |
config_error(MISSING_KEYS_ERROR, missing)
|
|
45 |
d['__dependencies'] = set()
|
|
46 |
if 'condition' in d:
|
|
47 |
d['__condition'] = SafeExpression(d['condition'])
|
|
48 |
try:
|
|
49 |
d['__condition'].validate(raises=True)
|
|
50 |
except InvalidExpression, e:
|
|
51 |
raise ImproperlyConfigured('invalid condition expression', e)
|
|
52 |
d['__dependencies'].update(d['__condition'].names())
|
|
53 |
d['__expression'] = SafeExpression(d['expression'])
|
|
54 |
try:
|
|
55 |
d['__expression'].validate(raises=True)
|
|
56 |
except InvalidExpression, e:
|
|
57 |
raise ImproperlyConfigured('invalid expression', e)
|
|
58 |
d['__dependencies'].update(d['__expression'].names())
|
|
59 |
d['__validated'] = True
|
|
60 |
yield d
|
|
61 |
|
|
62 |
def get_attribute_names(instance, ctx):
|
|
63 |
name = instance['name']
|
|
64 |
return ((name, instance.get('label', name)),)
|
|
65 |
|
|
66 |
def get_dependencies(instance, ctx):
|
|
67 |
return instance['__dependencies']
|
|
68 |
|
|
69 |
def get_attributes(instance, ctx):
|
|
70 |
if '__condition' in instance and not instance['__condition'](**ctx):
|
|
71 |
return {}
|
|
72 |
return {instance['name']: instance['__expression'](**ctx)}
|