asteval reference¶
-The asteval module has a pretty simple interface, providing an
-Interpreter
class which creates an Interpreter of expressions and
-code. There are a few options available to control what language features
-to support, how to deal with writing to standard output and standard error,
-and specifying the symbol table. There are also a few convenience
-functions: valid_symbol_name()
is useful for testing the validity of
-symbol names, and make_symbol_table()
is useful for creating symbol
-tables that may be pre-loaded with custom symbols and functions.
The Interpreter
class¶
--
-
- -class asteval.Interpreter(symtable=None, nested_symtable=False, user_symbols=None, writer=None, err_writer=None, use_numpy=True, max_statement_length=50000, minimal=False, readonly_symbols=None, builtins_readonly=False, config=None, **kws)¶ -
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
--
-
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’)
-by default ‘import’ and ‘importfrom’ are disabled, though they can be enabled.
-
By default, the symbol table will be created with make_symbol_table()
-that will include several standard python builtin functions, several
-functions from the math
module and (if available and not turned off)
-several functions from numpy.
The writer
argument can be used to provide a place to send all output
-that would normally go to sys.stdout
. The default is, of
-course, to send output to sys.stdout
. Similarly, err_writer
-will be used for output that will otherwise be sent to
-sys.stderr
.
The use_numpy
argument can be used to control whether functions from
-numpy are loaded into the symbol table.
Whether the user-code is able to overwrite the entries in the symbol table can
-be controlled with the readonly_symbols
and builtins_readonly
keywords.
Configuring which features the Interpreter recognizes¶
-The interpreter can be configured to enable or disable many language -constructs, named according to the AST node in the Python language definition.
-Table of optional Python AST nodes used asteval. The minimal configuration -excludes all of the nodes listed, to give a bare-bones mathematical language -but will full support for Python data types and array slicing.
---- -
-- - - - node name
- description
- in default config
- in minimal config
- - import
- import statements
- False
- False
- - importfrom
- from x import y
- False
- False
- - assert
- assert statements
- True
- False
- - augassign
- x += 1
- True
- False
- - delete
- delete statements
- True
- False
- - if
- if/then blocks
- True
- False
- - ifexp
- a = b if c else d
- True
- False
- - for
- for loops
- True
- False
- - formattedvalue
- f-strings
- True
- False
- - functiondef
- define functions
- True
- False
- - - print function
- True
- False
- - raise
- raise statements
- True
- False
- - listcomp
- list comprehension
- True
- False
- - dictcomp
- dict comprehension
- True
- False
- - setcomp
- set comprehension
- True
- False
- - try
- try/except blocks
- True
- False
- - while
- while blocks
- True
- False
- - - with
- with blocks
- True
- False
The minimal
configuration for the Interpreter will support many basic
-Python language constructs including all basic data types, operators, slicing.
-The default
configuration adds many language constructs, including
---
-- -
if-elif-else conditionals
- -
for loops, with
else
- -
while loops, with
else
- -
try-except-finally blocks
- -
with blocks
- -
augmented assignments:
x += 1
- -
if-expressions:
x = a if TEST else b
- -
list comprehension:
out = [sqrt(i) for i in values]
- -
set and dict comprehension, too.
- -
print formatting with
%
,str.format()
, or f-strings.- -
function definitions
The nodes listed in Table Table of optional Python AST nodes used asteval can be enabled and disabled individually with the appropriate
-no_NODE
or with_NODE
argument when creating the interpreter, or
-specifying a config
dictionary.
That is, you might construct an Interpreter as:
->>> from asteval import Interpreter
->>>
->>> aeval_nowhile = Interpreter(no_while=True)
->>>
->>> config = {'while': False, 'if': False, 'try': False,
- 'for': False, 'with': False}
->>> aveal_noblocks = Interpreter(config=config)
-
Passing, minimal=True
will turn off all the nodes listed in Table
-Table of optional Python AST nodes used asteval:
>>> from asteval import Interpreter
->>>
->>> aeval_min = Interpreter(minimal=True)
->>> aeval_min.config
-{'import': False, 'importfrom': False, 'assert': False, 'augassign': False,
-'delete': False, 'if': False, 'ifexp': False, 'for': False,
-'formattedvalue': False, 'functiondef': False, 'print': False,
-'raise': False, 'listcomp': False, 'dictcomp': False, 'setcomp': False,
-'try': False, 'while': False, 'with': False}
-
As shown above, importing Python modules with import module
or from
-module import method
can be enabled, but is disabled by default. To enable
-these, use with_import=True
and with_importfrom=True
, as
>>> from asteval import Interpreter
->>> aeval_max = Interpreter(with_import=True, with_importfrom=True)
-
or by setting the config dictionary as described above:
-Interpreter methods and attributes¶
-An Interpreter instance has many methods, but most of them are -implementation details for how to handle particular AST nodes, and should -not be considered as part of the usable API. The methods described be low, -and the examples elsewhere in this documentation should be used as the -stable API.
--
-
- -asteval.eval(expression[, lineno=0[, show_errors=True[, raise_errors=False]]])¶ -
evaluate the expression, returning the result.
- -
-
-
- -asteval.__call__(expression[, lineno=0[, show_errors=True[, raise_errors=False]]])¶ -
same as
-eval()
. That is:-->>> from asteval import Interpreter ->>> a = Interpreter() ->>> a('x = 1') -
instead of:
--->>> a.eval('x = 1') -
-
-
- -asteval.symtable¶ -
the symbol table where all data and functions for the Interpreter are stored -and looked up. By default, this is a simple dictionary with symbol names as -keys, and values of data and functions. If the
-nested_symtable
-option is used, the symbol tables will be a subclass of a dictionary with -more features, as discussed in Symbol Tables used in asteval.In either case, the symbol table can be accessed from the calling program -using the
-symtable
attribute of the Interpreter. This allows the -calling program to read, insert, replace, or remove symbols to -alter what symbols are known to your interpreter.
-
-
- -asteval.error¶ -
a list of error information, filled on exceptions. You can test this -after each call of the interpreter. It will be empty if the last -execution was successful. If an error occurs, this will contain a liste -of Exceptions raised.
-
-
-
- -asteval.error_msg¶ -
the most recent error message.
-
Symbol Tables used in asteval¶
-The symbol table holds all of the data used by the Interpreter. That is, when
-you execute a = b * cos(pi/3)
, the Interpreter sees that it needs to lookup
-values for b
, cos
, and pi
(it already knows =
, *
, /
,
-(
, and )
mean), and then set the value for a
. The place where it
-looks up and then sets those values for these assigned variables is the symbol
-table.
Historically, and by default, the symbol table in Asteval is a simple -dictionary with variable names as the keys, and their values as the -corresponding values. This is slightly simpler than in Python or roughly -equivalent to everything being “global”. This isn’t exactly true, and what -happens inside an Asteval Procedure (basically, a function) is a little -different as a special local symbol table (or Frame) is created for that -function, but it is mostly true.
-Symbol names are limited to being valid Python object names, and must match
-[a-zA-Z_][a-zA-Z0-9_]*
and not be a reserved word. The symbol table is held
-in the symtable
attribute of the Interpreter, and can be accessed and
-manipulated from the containing Python program. This allows the calling
-program to read, insert, replace, or remove symbols to alter what symbols are
-known to your interpreter. That is, it is perfectly valid to do something like
-this:
>>> from asteval import Interpreter
->>> aeval = Interpreter()
->>> aeval.symtable['x'] = 10
->>> aeval('sqrt(x)')
-3.1622776601683795
-
By default, the symbol table will be pre-loaded with many Python builtins,
-functions from the math
module, and functions from numpy
if available.
-You can control some of these settings or add symbols into the symbol table
-with the use_numpy
and user_symbols
arguments when creating an Interpreter.
-You can also build your own symbol table and pass that it, and use the
-readonly_symbols
and builtins_readonly
options to prevent some symbols to
-be writeable from within the Interpreter. You can also create your own symbol
-table, either as a plain dict, or with the make_symbol_table()
function,
-and alter that to use as the symtable
option when creating an Interpreter.
-That is, the calling program can fully control the symbol table, either
-pre-loading custom variables and functions or removing default functions.
New in version 0.9.31.
-New Style Symbol Table¶
-Beginning with version 0.9.31, there is an option to use a more complex and
-nested symbol table. This symbol table uses a "Group"
object which is a
-subclass of a Python dict that can also be used with object.attribute
syntax:
>>> from asteval import Interpreter
->>> aeval = Interpreter(nested_symtable=True)
->>> aeval('x = 3')
->>> aeval.symtable['x'] # as with default dictionary
-3
->>> aeval.symtable.x # new
-3
->>> aeval.symtable.y = 7 # new
->>> aeval('print(x+y)')
-10
-
As with the plain-dictionary symbol table, all symbols must be valid Python -identifiers, and cannot be reserved words.
-In addition, this symbol table can be nested – not flat – and may have a
-special attribute called _searchgroups
that give the name of sub-Groups to
-search for symbols. By default, when using this new-style symbol table, the
-mathematical functions imported from the math
and numpy
modules) are
-placed in a subgroup named math
(with more that 350 named functions and
-variables), and the _searchgroups
variable is set to the tuple
-('math',)
. When looking for the a symbol in an expression like a = b *
-cos( pi /3)
, the Interpreter will have to find and use the symbols names for
-b
, cos
and pi
. With the old-style symbol table, all of these
-must be in the flat dictionary, which makes it difficult to browse through the
-symbol table. With the new, nested symbol table, the names b
, cos
-and pi
are first looked for in the top-level Group. If not found there,
-they are looked for in the subgroups named in _searchgroups
, in order and
-returned as soon as one is found. That is the expectation is that b would be
-found in the “top-level user Group”, while cos
and pi
would be found in the
-math
Group, and that:
>>> aeval('a = b * cos( pi /3)')
->>> aeval('a = b * math.cos(math.pi /3)')
-
would be equivalent, as if you had imported a module that would automatically
-be searched: something between import math
and from math import *
. Though
-different from how Python works, if using Asteval as a domain-specific
-language, this nesting and automated searching can be quite useful.
Utility Functions¶
--
-
- -asteval.valid_symbol_name(name)¶ -
Determine whether the input symbol name is a valid name.
--
-
- Parameters: -
name (str) – name to check for validity.
-
-- Returns: -
valid – whether name is a a valid symbol name
-
-- Return type: -
- - -
This checks for Python reserved words and that the name matches -the regular expression
-[a-zA-Z_][a-zA-Z0-9_]
-
-
- -asteval.make_symbol_table(use_numpy=True, nested=False, top=True, **kws)¶ -
Create a default symboltable, taking dict of user-defined symbols.
--
-
- Parameters: -
-
-
numpy (bool, optional) – whether to include symbols from numpy [True]
-nested (bool, optional) – whether to make a “new-style” nested table instead of a plain dict [False]
-top (bool, optional) – whether this is the top-level table in a nested-table [True]
-kws (optional) – additional symbol name, value pairs to include in symbol table
-
-- Returns: -
symbol_table – a symbol table that can be used in asteval.Interpereter
-
-- Return type: -
dict or nested Group
-
-
To make and use a custom symbol table, one might do this:
-from asteval import Interpreter, make_symbol_table
-import numpy as np
-def cosd(x):
- "cos with angle in degrees"
- return np.cos(np.radians(x))
-
-def sind(x):
- "sin with angle in degrees"
- return np.sin(np.radians(x))
-
-def tand(x):
- "tan with angle in degrees"
- return np.tan(np.radians(x))
-
-syms = make_symbol_table(use_numpy=True, cosd=cosd, sind=sind, tand=tand)
-
-aeval = Interpreter(symtable=syms)
-print(aeval("sind(30)")))
-
which will print 0.5
.