Question about ast.literal_eval

Frank Millman frank at chagford.com
Mon May 20 09:26:02 EDT 2013


On 20/05/2013 10:07, Frank Millman wrote:
> On 20/05/2013 09:55, Chris Angelico wrote:
>> Is it a requirement that they be able to key in a constraint as a
>> single string? We have a similar situation in one of the systems at
>> work, so we divided the input into three(ish) parts: pick a field,
>> pick an operator (legal operators vary according to field type -
>> integers can't be compared against regular expressions, timestamps can
>> use >= and < only), then enter the other operand. Sure, that cuts out
>> a few possibilities, but you get 99.9%+ of all usage and it's easy to
>> sanitize.
>>
>> ChrisA
>>
>
> It is not a requirement, no. I just thought it would be a convenient
> short-cut.
>
> I had in mind something similar to your scheme above, so I guess I will
> have to bite the bullet and implement it.
>

Can anyone see anything wrong with the following approach. I have not 
definitely decided to do it this way, but I have been experimenting and 
it seems to work.

I store the boolean test as a json'd list of 6-part tuples. Each element 
of the tuple is a string, defined as follows -

0 - for the first entry in the list, the word 'check' (a placeholder - 
it is discarded at evaluation time), for any subsequent entries the word 
'and' or 'or'.

1 - left bracket - either '(' or ''.

2 - column name to check - it will be validated on entry.

3 - operator - must be one of '=', '!=', '<', '>', '<=', '>=', 'in', 
'is', 'is not'. At evaluation time, '=' is changed to '=='.

4 - value to compare - at evaluation time I call 
str(literal_eval(value)) to ensure that it is safe.

5 - right bracket - either ')' or ''.

At evaluation time I loop through the list, construct the boolean test 
as a string, and call eval() on it.

Here are some examples -

check = []
check.append(('check', '', 'name', 'in', "('abc', 'xyz')", ''))

check = []
check.append(('check', '', 'value', '>=', '0', ''))

check = []
check.append(('check', '(', 'descr', 'is not', 'None', ''))
check.append(('and', '', 'alt', 'is', 'None', ')'))
check.append(('or', '(', 'descr', 'is', 'None', ''))
check.append(('and', '', 'alt', 'is not', 'None', ')'))

I don't plan to check the logic - I will just display the exception if 
it does not evaluate.

It seems safe to me. Can anyone see a problem with it?

Frank





More information about the Python-list mailing list