Easy make mini-languages to do python things.
To install: pip install verb
Do things like this:
from verb import mk_executer
func_of_key = {
'plus': lambda x, y: x + y,
'minus': lambda x, y: x - y,
}
execute = mk_executer(func_of_key)
execute('3 minus 2 plus 1')
## 2
execute('9 minus 6')
## 3
Uses cases: In situations where you want to get some input from a user (from the web,
in a command line, etc.) that specifies a computation to be carried out, you know
(right) that you definitely shouldn't resort to using eval
or exec
.
Because it's dangerous for everyone involved -- let's just not go there.
verb
offers an alternative: Easily building minilanguages that will allow the user
to only execute the functions you choose, through a vocabulary you choose,
and everyone can go home (as) safe (as you allow).
In a nutshell, you make a key-to-func mapping (or use the default).
This func_of_key
mapping is what specifies your interpreter:
from verb import *
import operator as o
func_of_key = { # Note: Order represents precedence!
'-': o.sub,
'+': o.add,
'*': o.mul,
'/': o.truediv,
}
Now you have a minilanguage! Out-of-the-box it will allow you to "speak it in string" or "speak it in json/dict", but you can extend to enable the language to be written in any container you want.
If you give it a "command string":
command_str = '1 + 2 - 3 * 4 / 8'
command = Command(command_str, func_of_key)
command_str = '1 + 2 - 3 * 4 / 8' command = Command(command_str, func_of_key)
It will use func_of_key
to both parse it and replace the keys with an indication
that the corresponding function should be called.
command
is a callable object, and when you call it,
it executes it's instructions:
command()
1.5
It may be useful to see what the operation structure looks like
d = command.to_dict()
d
{'-': ({'+': (1, 2)}, {'*': (3, {'/': (4, 8)})})}
# Or if you read better with indents
from functools import partial
import json
from lined import Pipe
print_jdict = Pipe(partial(json.dumps, indent=2), print) # Note: Only works if your dict is JSON-izable.
print_jdict(d)
{
"-": [
{
"+": [
1,
2
]
},
{
"*": [
3,
{
"/": [
4,
8
]
}
]
}
]
}
That same dict can be used as a parameter to make the same command
command = Command(d, func_of_key)
command()
1.5
import operator as o
from typing import Callable, Mapping
from functools import partial
import pandas as pd
from lined import Pipe
from verb import str_to_basic_pyobj, Command
dflt_func_of_key_for_table_selection = { # Note: Order represents precedence!
'&': o.__and__,
'==': o.__eq__,
'<=': o.__le__,
'>=': o.__ge__,
'<': o.__lt__,
'>': o.__gt__,
}
def mk_table_selector(
table: pd.DataFrame,
func_of_key: Mapping[str, Callable] = dflt_func_of_key_for_table_selection
):
def leaf_processor(x):
x = str_to_basic_pyobj(x)
if x in table:
return table[x]
return x
run_command = Pipe(
partial(
Command.from_string,
func_of_key=func_of_key,
leaf_processor=leaf_processor
),
lambda f: f(),
lambda idx: table[idx],
)
return run_command
import pandas as pd
df = pd.DataFrame(
[{'source': 'audio', 'bt': 5, 'tt': 7, 'annot': 'cat'},
{'source': 'audio',
'bt': 6,
'tt': 9,
'annot': 'dog',
'comments': 'barks and chases cat away'},
{'source': 'visual', 'bt': 5, 'tt': 8, 'annot': 'cat'},
{'source': 'visual',
'bt': 6,
'tt': 15,
'annot': 'dog',
'comments': 'dog remains in view after bark ceases'}]
)
df
source | bt | tt | annot | comments | |
---|---|---|---|---|---|
0 | audio | 5 | 7 | cat | NaN |
1 | audio | 6 | 9 | dog | barks and chases cat away |
2 | visual | 5 | 8 | cat | NaN |
3 | visual | 6 | 15 | dog | dog remains in view after bark ceases |
run_command = mk_table_selector(df)
run_command('source == audio')
source | bt | tt | annot | comments | |
---|---|---|---|---|---|
0 | audio | 5 | 7 | cat | NaN |
1 | audio | 6 | 9 | dog | barks and chases cat away |
run_command('tt <= 8')
source | bt | tt | annot | comments | |
---|---|---|---|---|---|
0 | audio | 5 | 7 | cat | NaN |
2 | visual | 5 | 8 | cat | NaN |
run_command('source == audio & tt <= 8')
source | bt | tt | annot | comments | |
---|---|---|---|---|---|
0 | audio | 5 | 7 | cat | NaN |