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")
## 3Uses 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_commandimport 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 |