Source code for zcollection.expression
# Copyright (c) 2023 CNES
#
# All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
"""
Handles the partition selection expressions
===========================================
"""
from __future__ import annotations
from typing import Any, ClassVar
import ast
import dataclasses
import types
[docs]
@dataclasses.dataclass
class Expression:
"""Partitioning expressions.
Args:
expression: The expression to be evaluated
Raises:
NameError: If a variable is not defined.
Example:
>>> expr = Expression("year==2000 and month==1 and day in range(1, 12)")
"""
#: Compiled expression to be evaluated
code: types.CodeType
#: Known data members
__slots__: tuple[str, ...] = ('code', )
#: The builtins that are allowed in the expression.
BUILTINS: ClassVar[dict[str, Any]] = {'range': range}
def __init__(self, expression: str) -> None:
self.code = compile(ast.parse(expression, mode='eval'), ' ', 'eval')
[docs]
def __call__(self, variables: dict[str, Any]) -> Any:
try:
__locals: dict[str, Any] = {
name: variables[name]
for name in self.code.co_names if name not in self.BUILTINS
}
# pylint: disable=eval-used
# The eval function is used here to evaluate a simple expression.
# The only builtin functions allowed is the range function.
return eval(self.code, {'__builtins__': self.BUILTINS}, __locals)
# pylint: enable=eval-used
except KeyError as err:
raise NameError(f'name {err!s} is not defined') from err