File: __init__.py

package info (click to toggle)
dicteval 0.0.6-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 164 kB
  • sloc: python: 188; makefile: 3
file content (113 lines) | stat: -rw-r--r-- 3,653 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import functools
import json
import operator
import re

from .exceptions import FunctionNotFound


class LanguageSpecification:
    def __getitem__(self, item):
        if not item:
            item = "nop"
        if item.startswith('map'):
            item = "map"
        if item.startswith('filter'):
            item = "filter"
        try:
            return getattr(self, f"function_{item}")
        except AttributeError:
            raise FunctionNotFound(f"Function {item} not found.")


class BuiltinLanguage(LanguageSpecification):
    def function_any(self, value, evaluator, context):
        return any(evaluator(v, context) for v in value)

    def function_all(self, value, evaluator, context):
        return all(evaluator(v, context) for v in value)

    def function_eq(self, value, evaluator, context):
        value = [evaluator(v, context) for v in value]
        return not value or value.count(value[0]) == len(value)

    def function_if(self, value, evaluator, context):
        values = [evaluator(v, context) for v in value]
        condition, t = values[0:2]
        f = values[2] if len(values) > 2 else None
        return t if condition else f

    def function_neq(self, value, evaluator, context):
        return not self.function_eq(value, evaluator, context)

    def function_nop(self, value, evaluator, context):
        return evaluator(value, context)

    def function_not(self, value, evaluator, context):
        return not evaluator(value, context)

    def function_sum(self, value, evaluator, context):
        return sum(evaluator(v, context) for v in value)

    def function_mul(self, value, evaluator, context):
        return functools.reduce(operator.mul, (evaluator(v, context) for v in value))

    def function_divmod(self, value, evaluator, context):
        return divmod(*evaluator(value, context))

    def function_map(self, func, value, evaluator, context):
        return [func(e) for e in [evaluator(v, context) for v in value]]

    def function_filter(self, func, value, evaluator, context):
        return list(filter(func, (evaluator(v, context) for v in value)))

    def function_zip(self, value, evaluator, context):
        lists = [evaluator(v, context) for v in value]
        return list(zip(*lists))


class Evaluator:
    def __init__(self, language_spec):
        self.language = language_spec()

    def __call__(self, expr, context=None):
        if context is None:
            context = {}

        if isinstance(expr, dict):
            expression_keys = [k for k in expr if k.startswith("=")]
            if len(expression_keys) != 1:
                raise ValueError("Invalid expression")

            key = expression_keys[0]
            value = expr[key]

            if isinstance(value, dict):
                value = self(value, context)

            func = self.language[key[1:]]

            if func.__name__ in ['function_map', 'function_filter']:
                coll_func = re.search(r'(map|filter)\((.*)\)', key).groups()[1]
                return func(eval(coll_func), value, self, context)

            return func(value, self, context)

        if isinstance(expr, (list, tuple)):
            return [self(v, context) for v in expr]

        # TODO: implement a safe eval here
        if isinstance(expr, str):
            if expr.startswith("@{") and expr.endswith("}"):
                return eval(expr[2:-1], {}, context)
            if expr.startswith("!{") and expr.endswith("}"):
                return context[expr[2:-1]]

        return expr


dicteval = Evaluator(BuiltinLanguage)


def jsoneval(string):
    return dicteval(json.loads(string))