示例#1
0
    def _handle(self, node: ast.expr) -> Any:
        """
        This is where the evaluation happens.
        Users should use `__getitem__`, i.e. `evaluator[node]`,
        as it provides caching.

        :param node: an AST expression to evaluate
        :return: the value of the node
        """

        with suppress(ValueError):
            return ast.literal_eval(node)

        if isinstance(node, ast.Name):
            try:
                return self.names[node.id]
            except KeyError:
                raise CannotEval

        if isinstance(node, ast.Attribute):
            value = self[node.value]
            attr = node.attr
            return getattr_static(value, attr)

        if isinstance(node, ast.Subscript):
            value = self[node.value]
            index = node.slice
            if is_any(type(value), list, tuple, str, bytes, bytearray):
                if isinstance(index, ast.Index):
                    key = of_type(self[index.value], int, bool)
                    try:
                        return value[key]
                    except IndexError:
                        raise CannotEval
                elif isinstance(index, ast.Slice):
                    return value[slice(*[
                        None if p is None else of_type(self[p], int, bool)
                        for p in [index.lower, index.upper, index.step]
                    ])]
            elif is_any(type(value), dict) and isinstance(index, ast.Index):
                key = self[index.value]
                if (
                        safe_hash_key(key)

                        # Have to ensure that the dict only contains keys that
                        # can safely be compared via __eq__ to the index.
                        # Don't bother for massive dicts to not kill performance
                        and len(value) < 10000
                        and all(map(safe_hash_key, value))
                ):
                    try:
                        return value[key]
                    except KeyError:
                        raise CannotEval

        raise CannotEval
示例#2
0
    def _handle_binop(self, node):
        op_type = type(node.op)
        op = {
            ast.Add: operator.add,
            ast.Sub: operator.sub,
            ast.Mult: operator.mul,
            ast.Div: operator.truediv,
            ast.FloorDiv: operator.floordiv,
            ast.Mod: operator.mod,
            ast.Pow: operator.pow,
            ast.LShift: operator.lshift,
            ast.RShift: operator.rshift,
            ast.BitOr: operator.or_,
            ast.BitXor: operator.xor,
            ast.BitAnd: operator.and_,
        }.get(op_type)
        if not op:
            raise CannotEval
        left = self[node.left]
        hash_type = is_any(type(left), set, frozenset, dict, OrderedDict)
        left = of_standard_types(left, check_dict_values=False, deep=hash_type)
        formatting = type(left) in (str, bytes) and op_type == ast.Mod

        right = of_standard_types(
            self[node.right],
            check_dict_values=formatting,
            deep=formatting or hash_type,
        )
        try:
            return op(left, right)
        except Exception as e:
            raise CannotEval from e
示例#3
0
    def _handle_subscript(self, node):
        value = self[node.value]
        of_standard_types(value,
                          check_dict_values=False,
                          deep=is_any(type(value), dict, OrderedDict))
        index = node.slice
        if isinstance(index, ast.Slice):
            index = slice(*[
                None if p is None else self[p]
                for p in [index.lower, index.upper, index.step]
            ])
        elif isinstance(index, ast.ExtSlice):
            raise CannotEval
        else:
            if isinstance(index, ast.Index):
                index = index.value
            index = self[index]
        of_standard_types(index, check_dict_values=False, deep=True)

        try:
            return value[index]
        except Exception:
            raise CannotEval
示例#4
0
    def _handle_call(self, node):
        if node.keywords:
            raise CannotEval
        func = self[node.func]
        args = [self[arg] for arg in node.args]

        if (is_any(
                func,
                slice,
                int,
                range,
                round,
                complex,
                list,
                tuple,
                abs,
                hex,
                bin,
                oct,
                bool,
                ord,
                float,
                len,
                chr,
        ) or len(args) == 0 and is_any(func, set, dict, str, frozenset, bytes,
                                       bytearray, object) or len(args) >= 2
                and is_any(func, str, divmod, bytes, bytearray, pow)):
            args = [
                of_standard_types(arg, check_dict_values=False, deep=False)
                for arg in args
            ]
            try:
                return func(*args)
            except Exception as e:
                raise CannotEval from e

        if len(args) == 1:
            arg = args[0]
            if is_any(func, id, type):
                try:
                    return func(arg)
                except Exception as e:
                    raise CannotEval from e
            if is_any(func, all, any, sum):
                of_type(arg, tuple, frozenset, list, set, dict, OrderedDict,
                        deque)
                for x in arg:
                    of_standard_types(x, check_dict_values=False, deep=False)
                try:
                    return func(arg)
                except Exception as e:
                    raise CannotEval from e

            if is_any(func, sorted, min, max, hash, set, dict, ascii, str,
                      repr, frozenset):
                of_standard_types(arg, check_dict_values=True, deep=True)
                try:
                    return func(arg)
                except Exception as e:
                    raise CannotEval from e
        raise CannotEval