Skip to content Skip to sidebar Skip to footer

Reading Boolean Condition From Config File?

What's the best way to read a condition from a config file in Python using ConfigParser and json? I want to read something like: [mysettings] x >= 10 y < 5 and then apply it

Solution 1:

I don't think you want—or need—to use both configparserandjson, as both are sufficient by itself. Here's how to do it with each one:

Say you had a config file from a trusted source that contained something like this:

myconfig.ini

[mysettings]
other=stuff
conds=
    x >= 10
    y < 5
    x + y >= 6

It could parsed and used like this:

from __future__ import print_function
try:
    import configparser
except ImportError:  # Python 2
    import ConfigParser as configparser

get_lambda = lambda expr: lambda **kwargs: bool(eval(expr, kwargs))

cp = configparser.ConfigParser()
cp.read('myconfig.ini')

exprs = cp.get('mysettings', 'conds').strip()
conds = [expr for expr in exprs.split('\n')]

l = get_lambda(conds[0])
l2 = get_lambda(conds[1])
l3 = get_lambda(conds[2])

def formatted(l, c, **d):
    return '{:^14} : {:>10} -> {}'.format(
        ', '.join('{} = {}'.format(var, val) for var, val in sorted(d.items())), c, l(**d))

l = get_lambda(conds[0])
print('l(x=42): {}'.format(l(x=42)))
print()
print(formatted(l, conds[0], x=42))
print(formatted(l2, conds[1], y=6))
print(formatted(l3, conds[2], x=3, y=4))

Which would result in the following output:

l(x=42): True

    x = 42     :    x >= 10 -> True
    y = 6      :      y < 5 -> False
 x = 3, y = 4  : x + y >= 6 -> True

If the information the was instead kept in a JSON-format file similar to this:

myconfig.json

{
    "mysettings": {
        "other": "stuff",
        "conds": [
          "x >= 10",
          "y < 5",
          "x + y >= 6"
        ]
    }
}

It could be easily parsed with the json module and used in a similar fashion:

import json

withopen('myconfig.json') as file:
    settings = json.loads(file.read())

conds = settings['mysettings']['conds']

...the remainder would be the identical and produce the same results. i.e.:

l = get_lambda(conds[0])
print('l(x=42): {}'.format(l(x=42)))
print()
print(formatted(l, conds[0], x=42))
print(formatted(l2, conds[1], y=6))
print(formatted(l3, conds[2], x=3, y=4))

Solution 2:

This is an example using Python itself as the language for describing the config file:

config.py

mysettings = [
    lambda x: x >= 10,
    lambda y: y < 5,
]

main.py

from config import mysettings

a =42
b =300for i, conditionin enumerate(mysettings):
    forvaluein (a, b):
        result=condition(value)
        print "condition %s for value %s is: %s" % (i, value, result)

Output:

condition 0for value 42is: True
condition 0for value 300is: True
condition 1for value 42is: False
condition 1for value 300is: False

This of course assumes that the config file is considered trusted input, because by doing condition(value) you'll execute whatever function is defined in the config file.

But I don't see any way around that, regardless of what language you're using: conditions are expressions and therefore executable code. If you want to end up with a Python expression that you can just use in your code, you'll have to evaluate that expression sooner or later.

Edit:

If for some reason you really can't use Python, this is how you could do it with a config file in JSON:

config.json

{
  "mysettings": {
    "color": "Blue",
    "expressions": [
      "x >= 10",
      "y < 5"
    ]
  },
  "other_settings": {
    "color": "red"
  }
}

main.py

import json

x = 42y = 300


def eval_expr(expr, values):
    result = eval(expr, values.copy())
    print"The expression '%s' evaluates to '%s' for the values %r" % (
                                                    expr, result, values)
    return result


f = open('config.json')
data = json.loads(f.read())
settings = data["mysettings"]

for expr in settings['expressions']:
    values = dict(x=x, y=y)
    eval_expr(expr, values)

Result:

The expression 'x >= 10' evaluates to 'True'for the values {'y': 300, 'x': 42}
The expression 'y < 5' evaluates to 'False'for the values {'y': 300, 'x': 42}

Or, closer to your example:

x = 1
y = 2
values = dict(x=x, y=y)

e1 = settings['expressions'][0]
if eval_expr(e1, values):
    # do something
    pass

e2 = settings['expressions'][1]
if eval_expr(e2, values):
    # do something else
    pass

Result:

The expression 'x >= 10' evaluates to 'False'for the values {'y': 2, 'x': 1}
The expression 'y < 5' evaluates to 'True'for the values {'y': 2, 'x': 1}

Post a Comment for "Reading Boolean Condition From Config File?"