Project

General

Profile

0002-attributes_ng-sources-add-new-expression-source.patch

Benjamin Dauvergne, 14 August 2014 12:14 PM

Download (5.47 KB)

View differences:

Subject: [PATCH 2/3] attributes_ng/sources: add new expression source

You can define a python expression and a condition (also a python expression),
the defined attribute is created if the condition match, its value given
by the expression. Dependencies are automatically computed
from the expressions. It depends upon the library python-safe-expression.
 authentic2/app_settings.py                     |    1 +
 authentic2/attributes_ng/sources/expression.py |   72 ++++++++++++++++++++++++
 authentic2/validators.py                       |    8 +++
 requirements.txt                               |    1 +
 setup.py                                       |    1 +
 5 files changed, 83 insertions(+)
 create mode 100644 authentic2/attributes_ng/sources/expression.py
authentic2/app_settings.py
76 76
                 'authentic2.attributes_ng.sources.function',
77 77
                 'authentic2.attributes_ng.sources.django_user',
78 78
                 'authentic2.attributes_ng.sources.ldap',
79
                 'authentic2.attributes_ng.sources.expression',
79 80
                 ),
80 81
        definition='List of attribute backend classes or modules',
81 82
    ),
authentic2/attributes_ng/sources/expression.py
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)}
authentic2/validators.py
99 99
        raise ValidationError(_('password must contain characters '
100 100
            'from at least %d classes amon: lowercase letters, '
101 101
            'uppercase letters, digits, and punctuations') % min_class_count)
102

  
103
from safe_expression import SafeExpression, InvalidExpression
104

  
105
def safe_python_expression(value):
106
    try:
107
        SafeExpression(value).validate(raises=True)
108
    except InvalidExpression, e:
109
        raise ValidationError(e.args[0])
requirements.txt
10 10
dnspython
11 11
django-select2
12 12
django-tables2
13
safe-expression
setup.py
123 123
        'dnspython',
124 124
        'django-select2',
125 125
        'django-tables2',
126
        'safe-expression',
126 127
      ],
127 128
      zip_safe=False,
128 129
      classifiers=[
129
-