diff --git a/pyproject.toml b/pyproject.toml index 953352f3..93c339a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,7 @@ description = "Evaluate Lidar-Inertial Odometry on public datasets" readme = "README.md" requires-python = ">=3.11" dependencies = [ + "asteval>=1.0.6", "distinctipy>=1.3.4", "gdown>=5.2.0", "joblib>=1.5.2", diff --git a/python/evalio/cli/stats.py b/python/evalio/cli/stats.py index 5c63576d..8973f187 100644 --- a/python/evalio/cli/stats.py +++ b/python/evalio/cli/stats.py @@ -11,8 +11,6 @@ from rich import box from evalio import types as ty, stats - -import numpy as np import typer import distinctipy @@ -290,11 +288,9 @@ def evaluate_typer( if filter_str is None: filter_method = lambda r: True # noqa: E731 else: - filter_method = lambda r: eval( # noqa: E731 - filter_str, - {"__builtins__": None}, - {"np": np, **r}, - ) + from asteval import Interpreter + + filter_method = lambda r: Interpreter(user_symbols=r).eval(filter_str) original_filter = filter_method if only_complete: diff --git a/python/typings/asteval/__init__.pyi b/python/typings/asteval/__init__.pyi new file mode 100644 index 00000000..19b6e57a --- /dev/null +++ b/python/typings/asteval/__init__.pyi @@ -0,0 +1,73 @@ +""" +This type stub file was generated by pyright. +""" + +from typing import Any, Iterable, Optional + +class Interpreter: + """create an asteval Interpreter: a restricted, simplified interpreter + of mathematical expressions using Python syntax. + + Parameters + ---------- + symtable : dict or `None` + dictionary or SymbolTable to use as symbol table (if `None`, one will be created). + nested_symtable : bool, optional + whether to use a new-style nested symbol table instead of a plain dict [False] + user_symbols : dict or `None` + dictionary of user-defined symbols to add to symbol table. + writer : file-like or `None` + callable file-like object where standard output will be sent. + err_writer : file-like or `None` + callable file-like object where standard error will be sent. + use_numpy : bool + whether to use functions from numpy. + max_statement_length : int + maximum length of expression allowed [50,000 characters] + readonly_symbols : iterable or `None` + symbols that the user can not assign to + builtins_readonly : bool + whether to blacklist all symbols that are in the initial symtable + minimal : bool + create a minimal interpreter: disable many nodes (see Note 1). + config : dict + dictionay listing which nodes to support (see note 2)) + + Notes + ----- + 1. setting `minimal=True` is equivalent to setting a config with the following + nodes disabled: ('import', 'importfrom', 'if', 'for', 'while', 'try', 'with', + 'functiondef', 'ifexp', 'listcomp', 'dictcomp', 'setcomp', 'augassign', + 'assert', 'delete', 'raise', 'print') + 2. by default 'import' and 'importfrom' are disabled, though they can be enabled. + """ + def __init__( + self, + symtable: dict[Any, Any] = ..., + nested_symtable: bool = ..., + user_symbols: dict[Any, Any] = ..., + writer: Optional[Any] = ..., + err_writer: Optional[Any] = ..., + use_numpy: bool = ..., + max_statement_length: int = ..., + minimal: bool = ..., + readonly_symbols: Optional[Iterable[str]] = ..., + builtins_readonly: bool = ..., + config: dict[str, Any] = ..., + **kws: dict[Any, Any], + ) -> None: + pass + + def eval( + self, + expr: str, + lineno: int = ..., + show_errors: bool = ..., + raise_errors: bool = ..., + ) -> Any: + """Evaluate a single statement.""" + ... + +__all__ = [ + "Interpreter", +] diff --git a/uv.lock b/uv.lock index 17154e60..b7aeca51 100644 --- a/uv.lock +++ b/uv.lock @@ -25,6 +25,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, ] +[[package]] +name = "asteval" +version = "1.0.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f0/ad92c4bc565918713f9a4b54f06d06ec370e48079fdb50cf432befabee8b/asteval-1.0.6.tar.gz", hash = "sha256:1aa8e7304b2e171a90d64dd269b648cacac4e46fe5de54ac0db24776c0c4a19f", size = 52079, upload-time = "2025-01-19T21:44:03.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/ac/19dbba27e891f39feb4170b884da449ee2699ef4ebb88eefeda364bbbbcf/asteval-1.0.6-py3-none-any.whl", hash = "sha256:5e119ed306e39199fd99c881cea0e306b3f3807f050c9be79829fe274c6378dc", size = 22406, upload-time = "2025-01-19T21:44:01.323Z" }, +] + [[package]] name = "attrs" version = "25.3.0" @@ -285,6 +294,7 @@ name = "evalio" version = "0.3.0" source = { editable = "." } dependencies = [ + { name = "asteval" }, { name = "distinctipy" }, { name = "gdown" }, { name = "joblib" }, @@ -326,6 +336,7 @@ dev = [ [package.metadata] requires-dist = [ + { name = "asteval", specifier = ">=1.0.6" }, { name = "distinctipy", specifier = ">=1.3.4" }, { name = "gdown", specifier = ">=5.2.0" }, { name = "joblib", specifier = ">=1.5.2" },