tags:

views:

88

answers:

3

Hi,

I need to construct an if statement from the data coming from the client as below:

conditions: condition1, condition2, condition3, condition4 logical operators: lo1, lo2, lo3 (Possible values: "and" "or")

Eg.

if condition1 lo1 condition2 lo3 condition4:
    # Do something

I can think of eval/exec but not sure how safe they are! Any better approach or alternative? Appreciate your responses :)

PS: Client-side: Flex, Server-side: Python, over internet

Thanks

A: 

Ignacio's answer is the way to go. Go through your data, all the way building up your complex condition. But you'll have to use eval for the basic conditions:

condition = eval(conditions[0])
for cond, op in zip(conditions[1:], operators):
    lop = operator.and_ if op == "and" else operator.or_
    condition = lop(condition, eval(cond))

if condition:
    # Do something

You might want to make sure that there are no "evil" conditions in your condition list, e.g. by assuring that they always contain a comparison operator (==, <=, ....).

ThomasH
Using `eval` is insecure and fails in hard-to-catch ways.
Mike Graham
@Mike Doesn't question's author suggests insecure problem? What is in conditions no one knows. At least author didn't say anything specific about them. So using `eval` for this situation is OK, IMO
nailxx
@nailxx, The conditions' content was not revealed and we do not know if they are simple or very general. Even if they are rather general, that does not make using `eval` OK—it's still insecure, unpredictable, and dangerous. The exact use case will dictate the safer alternitive.
Mike Graham
@nailxx If the problem is insecure, it shouldn't be solved, it should be rephrased to be secure. It is bad to mislead beginners into writing insecure applications.
moshez
I think it is fair to assume that the OP is aware of these caveats. Maybe his use case is with a controlled client in a controlled environment (e.g. Intranet). The problem is also that of alternatives: If you really want to be sure, you need to parse the expressions.
ThomasH
+1  A: 

Don't use eval. It's a huge security risk. If your conditions are relatively simple, I would consider giving the user a decent flex GUI in which to enter them, not just a raw text area, but a real expression creation tool. Look at the "advanced search" features in any reasonably sophisticate search application for examples. Then take the data they have entered into the GUI widgets and represent it as objects. You would model your expression as a chain of Expressions (15 "duck" 5.3 etc), Operators (< > = != etc), and Conjunctions (AND OR NOT etc), or something along those lines. Then I would marshal these to JSON, unmarshal them into python objects on the server side python code, and evaluate them with custom python code.

Now, if you set of operators and expressions is very large, consider defining a Domain Specific Language and parsing that, which will be much safer than evaluating raw code. I haven't done a DSL myself, but I'm told python has good libraries for this (PLY might help).

Peter Lyons
It is a good idea of course to control the client environment when creating the conditions. But if you decline to use eval in general, you are down to parsing the expressions anyway, DSL or not. You can deploy heuristics with regexps, but if you _really_ want to be sure you need to parse.
ThomasH
+1  A: 

Define your own function that takes two conditions and an operator and evaluates:

def my_eval(condition1, lo, condition2)
    return {
      'and': condition1 and condition2,
      'or': condition1 or condition2
           }[lo]

and then evaluate the lot:

condition = conditions[0]
for cond, op in zip(conditions[1:], operators):
    condition = my_eval(condition, op, cond)

Feel free to preprocess condition1 and condition2 in my_eval, you probably don't intend to truth test the strings :-)

Will Hardy
Exactly. Without "preprocessing" your are just taking the truth value of strings, which is True for any string other than the empty string. Without it, your code will probably not achieve the OP's goal. The preprocessing will be 'eval' or something similar.
ThomasH